赞
踩
<EditText
<requestFocus/>//可获取焦点
</EditText>
gradle ModuleName:dependencies//查看依赖树状图
//定位到冲突的依赖后排除
compile ('com.awesome:someawesomelibrary:1.0.0.0') {
exclude group: 'com.google.android', module: 'android'
}
//滚动时抛出索引越界异常...
//java.lang.ArrayIndexOutOfBoundsException: length=2; index=2
//注意类型不能随便定义 范围应该为 0...getViewTypeCount-1
@Override
public int getItemViewType(int position) {
DataItem dataItem = map.get(position);
return dataItem!=null?0:1;
}
//复制文件
private void copyFile(String oldPath, String newPath) {
try {
int bytesum = 0;
int byteread = 0;
File oldfile = new File(oldPath);
if (oldfile.exists()) { //文件不存在时
InputStream inStream = new FileInputStream(oldPath); //读入原文件
FileOutputStream fs = new FileOutputStream(newPath);
byte[] buffer = new byte[1444];
int length;
while ((byteread = inStream.read(buffer)) != -1) {
bytesum += byteread; //字节数 文件大小
//System.out.println(bytesum);
fs.write(buffer, 0, byteread);
}
inStream.close();
}
} catch (Exception e) {
System.out.println("复制单个文件操作出错");
e.printStackTrace();
}
}
//通过一个像素点进行进程保活,被万恶的腾讯QQ带坏了
windowManager = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
surfaceView = new SurfaceView(this);
mSurfaceHolder = surfaceView.getHolder();
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
1, 1,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT
);
layoutParams.gravity = Gravity.LEFT | Gravity.TOP;//放在左上角
windowManager.addView(surfaceView, layoutParams);
mSurfaceHolder.addCallback(this);//看了下,什么也没做
cb:
android:focusable="false"
android:clickable="false"
android:focusableInTouchMode="false"
item的viewgroup中:
android:descendantFocusability="blocksDescendants"
beforeDescendants:viewgroup会优先其子类控件而获取到焦点
afterDescendants:viewgroup只有当其子类控件不需要获取焦点时才获取焦点
blocksDescendants:viewgroup会覆盖子类控件而直接获得焦点
res/style
<style name="NoShadowDialog" parent="@android:style/Theme.Dialog">
<item name="android:windowIsFloating">true</item>
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:backgroundDimAmount">0.5</item>
</style>
View dialogLayout = LayoutInflater.from(OrderFoodActivity.this)
.inflate(R.layout.dialog_select_food_type, null, false);
AlertDialog alertDialog = new AlertDialog
.Builder(OrderFoodActivity.this,R.style.NoShadowDialog)
.create();
alertDialog.show();
WindowManager.LayoutParams attributes = alertDialog.getWindow().getAttributes();
attributes.width= FrameLayout.LayoutParams.WRAP_CONTENT;
attributes.height= FrameLayout.LayoutParams.WRAP_CONTENT;
alertDialog.getWindow().setAttributes(attributes);
alertDialog.setContentView(dialogLayout);
alertDialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
//FragmentTabHost的宽度必须为固定值,否则不显示,应该是测量的问题
<HorizontalScrollView
android:layout_width="1080dp"
android:layout_height="wrap_content"
android:scrollbars="none">
<LinearLayout
android:layout_width="2160dp"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v4.app.FragmentTabHost
android:id="@android:id/tabhost"
android:layout_width="2160dp"
android:layout_height="wrap_content"/>
</LinearLayout>
</HorizontalScrollView>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#fff"/>
<corners android:radius="6dp"/>
<stroke android:color="#b5b5b5" android:width="1dp"/>
</shape>
compile 'com.android.support:design:25.3.1'
<android.support.design.widget.TabLayout
android:id="@+id/tablayout_orderfood_act"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_marginTop="0dp"
app:tabIndicatorColor="#3af"//指示器颜色
app:tabSelectedTextColor="#000"//选中后文字颜色
app:tabTextColor="#000"//tab中文字颜色
app:tabMode="fixed"//是否固定
app:tabGravity="center"//tab的gravity
android:background="#fff" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/linearLayout3"/>
tab_ll.addTab(tab_ll.newTab().setText("今日菜单"));
tab_ll.addTab(tab_ll.newTab().setText("我的订餐"));
tab_ll.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
ArrayList<String> datas=new ArrayList<>();
for (int i = 0; i < 2; i++) {
datas.add("哈哈"+i);
}
ArrayList<CharSequence> titles=new ArrayList<>();
titles.add("今日菜单");
titles.add("我的订餐");
vp.setAdapter(new CommonPagerAdapter<String>(OrderFoodMainActivity.this,datas,titles) {
@Override
public View getView(ViewGroup container, String data, int position) {
View view = LayoutInflater.from(mContext).inflate(R.layout.pop_scoretype, container, false);
return view;
}
});
tab_ll.setupWithViewPager(vp);
<EditText
android:id="@+id/editText_username"
android:layout_width="0dp"
android:layout_height="30dp"
//通过属性, android:digits中的内容才能被输入
android:digits=
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
android:layout_weight="1"
android:background="@color/white"
android:inputType="text"
android:ems="10"
android:hint="账 号"
android:padding="5dp"
android:textSize="13dp">
</EditText>
//使用正则来过滤
et.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
String content=et.getText().toString();
String regEx="[^a-zA-Z0-9]";
Pattern pattern = Pattern.compile(regEx);
Matcher matcher = pattern.matcher(content);
String trimedContent = matcher.replaceAll("").trim();
if (!content.equals(trimedContent)){
et.setText(trimedContent);
et.setSelection(trimedContent.length());
}
}
@Override
public void afterTextChanged(Editable editable) {
}
});
android:ems = "10" 设置TextView或者Edittext的宽度为10个字符的宽度。当设置该属性后,控件显示的长度就为10个字符的长度,超出的部分将不显示。
String[] strings1 = datas.toArray(new String[datas.size()]);
public static void download(Context context){
String url="http://192.168.0.103:8080/SchoolPC/res/Score/11010001/11010001G0C0-1512632769413.xlsx";
String cachePath = CachePathUtils.getCachePath(context);
String fileName = url.substring(url.lastIndexOf("/") + 1);
File file = new File(cachePath,fileName);
client.get(url, new FileAsyncHttpResponseHandler(file) {
@Override
public void onFailure(int i, Header[] headers, Throwable throwable, File file) {
Logger.d("失败"+i);
}
@Override
public void onSuccess(int i, Header[] headers, File file) {
Logger.d("成功"+file.getAbsolutePath());
}
});
}
<activity android:name=".iu.gridview.score.PostActivity" android:exported="true">
<intent-filter>
<data android:mimeType="application/msword"/>
<data android:mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.document"/>
<data android:mimeType="application/vnd.ms-excel"/>
<data android:mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"/>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
public class HomeworkExAdapter extends BaseExpandableListAdapter {
Context mContext;
ArrayList<JsonHomeworkBean> mDatas;
String mLoginName;
deleteCallback mDeleteCallback;
public HomeworkExAdapter(Context context, String loginName, ArrayList<JsonHomeworkBean> datas,deleteCallback callback) {
mContext = context;
mLoginName = loginName;
mDatas = datas;
mDeleteCallback=callback;
}
public void setDatas(ArrayList<JsonHomeworkBean> datas){
mDatas=datas;
notifyDataSetChanged();
}
@Override
public int getGroupCount() {
return mDatas != null ? mDatas.size() : 0;
}
@Override
public int getChildrenCount(int groupPosition) {
return mDatas.get(groupPosition).getDatas() == null ? 0 : mDatas.get(groupPosition).getDatas().size();
}
@Override
public JsonHomeworkBean getGroup(int groupPosition) {
return mDatas.get(groupPosition);
}
@Override
public JsonHomeworkBean.DatasBean getChild(int groupPosition, int childPosition) {
return mDatas.get(groupPosition).getDatas().get(childPosition);
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
//不知道有啥用...算啦不管了
@Override
public boolean hasStableIds() {
return false;
}
ParentViewHolder mParentViewHolder;
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.exlv_parent_item_homework_message, parent, false);
mParentViewHolder = new ParentViewHolder(convertView);
convertView.setTag(mParentViewHolder);
} else {
mParentViewHolder = (ParentViewHolder) convertView.getTag();
}
JsonHomeworkBean jsonHomeworkBean = mDatas.get(groupPosition);
if (jsonHomeworkBean.getStatus() == 1) {
mParentViewHolder.count.setText(jsonHomeworkBean.getDatas().size() + "");
mParentViewHolder.title.setText(jsonHomeworkBean.getClassName());
}
return convertView;
}
ChildViewHolder mChildViewHolder;
@Override
public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.exlv_child_homework_message, parent, false);
mChildViewHolder = new ChildViewHolder(convertView);
convertView.setTag(mChildViewHolder);
} else {
mChildViewHolder = (ChildViewHolder) convertView.getTag();
}
JsonHomeworkBean.DatasBean datasBean = mDatas.get(groupPosition).getDatas().get(childPosition);
if (datasBean == null)
return convertView;
List<String> imgList = datasBean.getImgList();
final int id = datasBean.getId();
mChildViewHolder.teacherName.setText(datasBean.getT_name());
mChildViewHolder.subjectName.setText(datasBean.getSubject_name());
mChildViewHolder.homeworkContent.setText(datasBean.getContent());
mChildViewHolder.time.setText(TimeUtils.getLocalTimeString(datasBean.getCreate_date().getTime()));
mChildViewHolder.delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mDeleteCallback!=null)
mDeleteCallback.delete(id);
}
});
mChildViewHolder.pics.setAdapter(
new HolderAdapter<String, CommonViewHolder2>(mContext, imgList, R.layout.item_gv_single_iv) {
@Override
protected void bindDatas(CommonViewHolder holder, String data, int position) {
ImageView iv=holder.getView(R.id.iv_single_item);
String url = AsyncHttpAsynchttpUtil.uhtp + "SchoolPC/res/homeworks/" + data;
Picasso.with(mContext)
.load(url)
.fit()
.into(iv);
}
});
FixedViewUtil.setListViewHeightBasedOnChildren(mChildViewHolder.pics, 3);
return convertView;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return false;
}
static class ParentViewHolder {
ImageView iv;
TextView title;
TextView count;
public ParentViewHolder(View rootView) {
iv = (ImageView) rootView.findViewById(R.id.iv_hint_homework_message_act_exlvparent);
title = (TextView) rootView.findViewById(R.id.tv_title_homework_message_act_exlvparent);
count = (TextView) rootView.findViewById(R.id.tv_count_homework_message_act_exlvparent);
}
}
static class ChildViewHolder {
TextView subjectName;
TextView teacherName;
TextView delete;
TextView homeworkContent;
GridView pics;
TextView time;
public ChildViewHolder(View rootView) {
subjectName = (TextView) rootView.findViewById(R.id.tv_subject_name);
teacherName = (TextView) rootView.findViewById(R.id.tv_teacher_name);
delete = (TextView) rootView.findViewById(R.id.tv_delete);
homeworkContent = (TextView) rootView.findViewById(R.id.tv_homework_content);
pics = (GridView) rootView.findViewById(R.id.gv_homework_pictures);
time = (TextView) rootView.findViewById(R.id.tv_time);
}
}
public interface deleteCallback{
void delete(int deleteId);
}
}
从当前设置状态更新弹出窗口的状态,如果当前正在显示,
public class PopupWindows extends PopupWindow {
public PopupWindows(Context mContext, View parent) {
super(mContext);
View view = View
.inflate(mContext, R.layout.item_popupwindows, null);
view.startAnimation(AnimationUtils.loadAnimation(mContext,
R.anim.fade_ins));
LinearLayout ll_popup = (LinearLayout) view
.findViewById(R.id.ll_popup);
ll_popup.startAnimation(AnimationUtils.loadAnimation(mContext,
R.anim.push_bottom_in_2));
setWidth(LayoutParams.FILL_PARENT);
setHeight(LayoutParams.FILL_PARENT);
setBackgroundDrawable(new BitmapDrawable());
setFocusable(true);
setOutsideTouchable(true);
setContentView(view);
showAtLocation(parent, Gravity.BOTTOM, 0, 0);
update();
Button bt1 = (Button) view
.findViewById(R.id.item_popupwindows_camera);
Button bt2 = (Button) view
.findViewById(R.id.item_popupwindows_Photo);
Button bt3 = (Button) view
.findViewById(R.id.item_popupwindows_cancel);
bt1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
photo();
dismiss();
}
});
bt2.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(PublishedActivity.this,
TestPicActivity.class);
startActivity(intent);
dismiss();
}
});
bt3.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
dismiss();
}
});
}
}
1)AlertDialog是非阻塞线程的,Popupwindow是阻塞线程的。
2)Dialog没法设置宽为整个屏幕宽,总有点边界。Popupwindow可以。
1、Dialog及设置Dialog的动画
设置Dialog的位置和大小与加载的布局文件无关。需自己设置dialog参数。
1)设置Dialog位置:
设置位置时必须先指定Dialog的gravity属性,否则指定大小无用。
/*
* lp.x与lp.y表示相对于原始位置的偏移.
* 当参数值包含Gravity.LEFT时,对话框出现在左边,所以lp.x就表示相对左边的偏移,负值忽略.
* 当参数值包含Gravity.RIGHT时,对话框出现在右边,所以lp.x就表示相对右边的偏移,负值忽略.
* 当参数值包含Gravity.TOP时,对话框出现在上边,所以lp.y就表示相对上边的偏移,负值忽略.
* 当参数值包含Gravity.BOTTOM时,对话框出现在下边,所以lp.y就表示相对下边的偏移,负值忽略.
* 当参数值包含Gravity.CENTER_HORIZONTAL时
* ,对话框水平居中,所以lp.x就表示在水平居中的位置移动lp.x像素,正值向右移动,负值向左移动.
* 当参数值包含Gravity.CENTER_VERTICAL时
* ,对话框垂直居中,所以lp.y就表示在垂直居中的位置移动lp.y像素,正值向右移动,负值向左移动.
* gravity的默认值为Gravity.CENTER,即Gravity.CENTER_HORIZONTAL |
* Gravity.CENTER_VERTICAL.
*
* 本来setGravity的参数值为Gravity.LEFT | Gravity.TOP时对话框应出现在程序的左上角,但在
* 我手机上测试时发现距左边与上边都有一小段距离,而且垂直坐标把程序标题栏也计算在内了,
* Gravity.LEFT, Gravity.TOP, Gravity.BOTTOM与Gravity.RIGHT都是如此,据边界有一小段距离
*/
lp.y=90;
2)去标题:
[java] view plain copy
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);<span style="color:#cc0000;">//要在创建完dialog后就调用,否则报错
3)设置Dialog的宽和高
[java] view plain copy
WindowManager wm = getWindowManager();
Display display = wm.getDefaultDisplay();
android.view.WindowManager.LayoutParams lp = dialog.getWindow().getAttributes();
lp.width = display.getWidth();
lp.height =LayoutParams.WRAP_CONTENT;
dialog.getWindow().setAttributes(lp);
2、Popupwindow
1)设置显示位置特别方便:
showAsDropDown(View anchor):相对某个控件的位置(正左下方),无偏移。
showAsDropDown(View anchor, int xoff, int yoff):相对某个控件的位置,有偏移。
showAtLocation(View parent, int gravity, int x, int y):相对于父控件的位置(例如正中央Gravity.CENTER,下方Gravity.BOTTOM等),可以设置偏移或无偏移。
2)点击Popupwindow以外区域自动消失
注意一定要设置backgroundDrawable
[java] view plain copy
//参数也可以是下面这俩值
//1、getResources().getDrawable(R.drawable.abc)
//2、getWallpaper()
//当你发现有背景色时,需给布局文件设置背景色,这样即可覆盖系统自带的背景色。
pw.setBackgroundDrawable(new BitmapDrawable());
pw.setOutsideTouchable(true);
有种说法是pw.setFocusable(false);,则不点击区域以外不会消失。经测试,此种说法不对。
public static String SDPATH = Environment.getExternalStorageDirectory()
+ "/formats/";
//删除文件夹
public static void deleteDir() {
File dir = new File(SDPATH);
if (dir == null || !dir.exists() || !dir.isDirectory())
return;
//通过递归删除所有的文件和文件夹
for (File file : dir.listFiles()) {
if (file.isFile())
file.delete();
else if (file.isDirectory())
deleteDir();
}
dir.delete();// 删除目录本身
}
ablv.setSelector(new ColorDrawable(Color.TRANSPARENT));
apply plugin: 'com.android.application'
改为
apply plugin: 'com.android.library'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
//删除applicationId
applicationId "com.junx.x5demo"
minSdkVersion 19
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
与project的编辑版本要一致
//初始化Webview
webView.loadUrl("file:///android_asset/EduMessage.html");
webView.getSettings().setJavaScriptEnabled(true);
WebSettings webSettings = webView.getSettings();
//设置是否支持缩放
webSettings.setSupportZoom(true);
//开启js
webSettings.setJavaScriptEnabled(true);
//设置打开时js可以被打开
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
//是否使用内置的缩放机制
webSettings.setBuiltInZoomControls(true);
//是否开启插件
webSettings.setPluginState(WebSettings.PluginState.ON);
//是否使用标记的中宽高
webSettings.setUseWideViewPort(true);
//设置是否考虑到屏幕宽高
webSettings.setLoadWithOverviewMode(true);
webSettings.setTextSize(WebSettings.TextSize.LARGEST);
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int mDensity = metrics.densityDpi;
if (mDensity == 240) {
webSettings.setDefaultZoom(ZoomDensity.FAR);
} else if (mDensity == 160) {
webSettings.setDefaultZoom(ZoomDensity.MEDIUM);
} else if (mDensity == 120) {
webSettings.setDefaultZoom(ZoomDensity.CLOSE);
} else if (mDensity == DisplayMetrics.DENSITY_XHIGH) {
webSettings.setDefaultZoom(ZoomDensity.FAR);
} else if (mDensity == DisplayMetrics.DENSITY_TV) {
webSettings.setDefaultZoom(ZoomDensity.FAR);
}
webView.addJavascriptInterface(this,"contact");
@JavascriptInterface
public void showContent() {
webView.loadUrl("javascript:showContent('" + mData.getContent() + "')");
}
@JavascriptInterface
public void showTitle() {
webView.loadUrl("javascript:showTitle('" + mData.getTitle() + "')");
}
List中的Item的LayoutParam是直接继承自ViewPager中的LayoutParam。 不包含有margin信息。 所以在ListView中父节点设置的值会失效。
<TextView
android:id="@+id/tv_content_edu_message_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:ellipsize="end"//...在末尾
android:maxLines="1"
android:text="content"
android:textSize="13dp"
/>
.ttf
typeface = Typeface.createFromAsset(context.assets, "fonts/yummy_bread.ttf")
view.findViewById<TextView>(R.id.message).apply {
typeface = getTypeface(context)
text = message
}
修改源码:
打开java文件,切换到project视图,点击project视图上方的瞄准镜,定位到文件的位置,复制黏贴即可
BitmapFactory.decodeFile(file.getAbsolutePath());
git merge –no-ff 可以保存你之前的分支历史。能够更好的查看 merge历史,以及branch 状态。
git merge 则不会显示 feature,只保留单条分支记录。
//webview常用方法
webView.loadUrl("file:///android_asset/campusDynami.html");
webView.getSettings().setJavaScriptEnabled(true);
WebSettings webSettings = webView.getSettings();
webSettings.setSupportZoom(true);
webSettings.setJavaScriptEnabled(true);
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
webSettings.setBuiltInZoomControls(true);//support zoom
webSettings.setPluginState(WebSettings.PluginState.ON);//support flash
webSettings.setUseWideViewPort(true);// 这个很关键
webSettings.setLoadWithOverviewMode(true);
webSettings.setTextSize(WebSettings.TextSize.LARGEST);
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int mDensity = metrics.densityDpi;
if (mDensity == 240) {
webSettings.setDefaultZoom(ZoomDensity.FAR);
} else if (mDensity == 160) {
webSettings.setDefaultZoom(ZoomDensity.MEDIUM);
} else if (mDensity == 120) {
webSettings.setDefaultZoom(ZoomDensity.CLOSE);
} else if (mDensity == DisplayMetrics.DENSITY_XHIGH) {
webSettings.setDefaultZoom(ZoomDensity.FAR);
} else if (mDensity == DisplayMetrics.DENSITY_TV) {
webSettings.setDefaultZoom(ZoomDensity.FAR);
}
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
<script type="text/javascript">
<!--第一步,在Html中定义js方法-->
function showContent(jsondata){
alert(title);
document.getElementById("personts").innerHTML=jsondata;
}
function showTitle(jsondata){
alert(title);
document.getElementById("title").innerHTML=jsondata;
}
</script>
<!--修正图片尺寸,设置宽度最大值,高度自适应防变形-->
<style>img{max-width:100% !important; height:auto !important;}</style>
</head>
<!--在加载网页时,调用js的两个方法-->
<body onload="javascript:contact.showContent();javascript:contact.showTitle()" bgcolor="#efeff4">
<!--白色圆角背景-->
<div style=" background-color:white; border-radius:10px; margin:8px; padding-left:10px; padding-right:10px; padding-top:5px; padding-bottom:5px; box-shadow:3px 3px 2px 2px lightgray; ">
<!--标题-->
<p id="title" style="font-size:0.8em;text-align: center; color:#2191FB; margin:0px;" >
</p>
<!--横线-->
<div style="background-color:#efeff4; width:100%; height:1px; margin-top:5px; margin-bottom:5px;"></div>
<div style="font-size:0.5em;" id="personts"></div>
</div>
</body>
</html>
//在java中定义回调类,调用js中方法
public final class JSObjet {
@JavascriptInterface
public void showContent() {
webView.loadUrl("javascript:showContent('" + LogConten + "')");
}
@JavascriptInterface
public void showTitle() {
webView.loadUrl("javascript:showTitle('" + LogTitle + "')");
}
}
//在webview中使用回调类
webView.addJavascriptInterface(new JSObjet(), "contact");
Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
Calendar c = Calendar.getInstance();
DatePickerDialog dialog = new DatePickerDialog(this, new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
month+=1;//因为它是从0开始计算的
}
}, c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH));
dialog.setTitle("请选择");
dialog.setCanceledOnTouchOutside(true);
dialog.setCancelable(true);
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, "取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
dialog.show();
{"code":1,"info":"success","results":{"id":"1","name":"hehe"}}
results对应的应该是一个实体类,如果这个时候想把他解析为String或者List就会出现异常。
如果参考使用GsonForm处理后的数据模型,几乎不会出现问题;加入result后面的内容可能在请求时会因为某些原因会存在格式上的变化,这个时候就有出现该异常的风险。Gson中,关键字后面出现""引起来的内容将会被只认为是STRING,“{}”只被认为是类,“[]”只被认为是List,这个几乎是强制性的。
就是说如果你的实体预计是获取String的变量,但是关键字后面对应的却出现了“{”或“[”,那么这个转换将被认为是错误的,抛出异常。
解决办法:后台输出稳定的Gson格式。
解决办法2:换到新版本的FastJson
compile 'com.alibaba:fastjson:1.2.41'
1.翻墙 chrome内核浏览器
2.gradle
//抓包工具
compile 'com.facebook.stetho:stetho:1.3.1'
compile 'com.facebook.stetho:stetho-okhttp3:1.3.1'
3. okhttp中添加插值器
okHttpClient=new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.addNetworkInterceptor(new StethoInterceptor())
.build();
4. 初始化 Stetho.initializeWithDefaults(this);
5. chrome://inspect/#devices
说明编译.so文件时使用了较低版本sdk
而project 中的配置 targetSdkVersion22 大于so编译时使用的sdkversion,所以只需要把功能中
的targetSdkVersion降低即可
defaultConfig {
applicationId “com.example”
minSdkVersion 16
targetSdkVersion 22
versionCode 1
versionName “1.0”
}
SparseArray比HashMap更省内存,在某些条件下性能更好,主要是因为它避免了对key的自动装箱(int转为Integer类型),它内部则是通过两个数组来进行数据存储的,一个存储key,另外一个存储value,为了优化性能,它内部对数据还采取了压缩的方式来表示稀疏数组的数据,从而节约内存空间,我们从源码中可以看到key和value分别是用数组表示:
private int[] mKeys;
private Object[] mValues;
SparseArray在存储和读取数据时候,使用的是二分查找法
public void put(int key, E value);
public void delete(int key);
public void remove(int key);//内部还是调用了delete
public E get(int key);
public E get(int key, E valueIfKeyNotFound);
public int keyAt(int index);
public E valueAt(int index);
SparseArray应用场景:
虽说SparseArray性能比较好,但是由于其添加、查找、删除数据都需要先进行一次二分查找,所以在数据量大的情况下性能并不明显,将降低至少50%。
满足下面两个条件我们可以使用SparseArray代替HashMap:
数据量不大,最好在千级以内
key必须为int类型,这中情况下的HashMap可以用SparseArray代替:
ArrayMap是一个<key,value>映射的数据结构,它设计上更多的是考虑内存的优化,内部是使用两个数组进行数据存储,一个数组记录key的hash值,另外一个数组记录Value值,它和SparseArray一样,也会对key使用二分法进行从小到大排序,在添加、删除、查找数据的时候都是先使用二分查找法得到相应的index,然后通过index来进行添加、查找、删除等操作,所以,应用场景和SparseArray的一样,如果在数据量比较大的情况下,那么它的性能将退化至少50%。
如果我们要兼容aip19以下版本的话,那么导入的包需要为v4包
import android.support.v4.util.ArrayMap;
1、如果key的类型已经确定为int类型,那么使用SparseArray,因为它避免了自动装箱的过程,如果key为long类型,它还提供了一个LongSparseArray来确保key为long类型时的使用
2、如果key类型为其它的类型,则使用ArrayMap
public class BlankFragment extends Fragment {
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
public BlankFragment() {
}
public static BlankFragment newInstance(String param1, String param2) {
BlankFragment fragment = new BlankFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_blank, container, false);
View fl = view.findViewById(R.id.fl);
int i = new Random().nextInt(5);
int color=0;
switch (i){
case 0:
color= Color.RED;
break;
case 1:
color=Color.BLUE;
break;
case 2:
color=Color.GREEN;
break;
case 3:
color=Color.YELLOW;
break;
case 4:
color=Color.BLACK;
break;
case 5:
color=Color.GRAY;
break;
}
fl.setBackgroundColor(color);
View btn = view.findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mListener.onFragmentInteraction("你好啊");
}
});
return view;
}
public void onButtonPressed(String uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
void onFragmentInteraction(String uri);
}
}
前者会将所有的Fragment缓存在内存中,后者只缓存当前item的前后各一个Fragment
简单来说前者更流畅但吃内存
StringBuffer stringBuffer = new StringBuffer(title);
stringBuffer.insert(2,"\n");
title=stringBuffer.toString();
ctrl +;
ctrl -;
//给actionbar添加一个左上角的返回图标
actionBar.setDisplayHomeAsUpEnabled(true)
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitle(demo.titleResId);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
//添加返回图标
if (actionBar!=null)
actionBar.setDisplayHomeAsUpEnabled(true);
1.
在a类中创建一个静态的mHandler,不进行初始化
2.
在b类中创建a的实例的时候,初始化mHandler
3.
那么就可以在a类中调用mHandler,从而实现跨类通讯
listview.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
public static String getWifiIp (Context context)
{
String wifiStr = "";
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
if (wifiManager.isWifiEnabled()
&& wifiManager.getWifiState() == wifiManager.WIFI_STATE_ENABLED){
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
if (wifiInfo != null) {
int ipAddress = wifiInfo.getIpAddress();
if (ipAddress == 0){
wifiStr = "";
}
else{
wifiStr = ((ipAddress & 0xff) + "." + (ipAddress >> 8 & 0xff)
+ "." + (ipAddress >> 16 & 0xff) + "." + (ipAddress >> 24 & 0xff));
}
}
}
return wifiStr;
}
public void lockMethod() {
ReentrantLock myLock = new ReentrantLock();
myLock.lock();
try{
// 受保护的代码段
//critical section
} finally {
// 可以保证发生异常 锁可以得到释放 避免死锁的发生
myLock.unlock();
}
}
//似乎是需要一点点的时间进行初始化
new Timer().schedule(new TimerTask() {
@Override
public void run() {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
banner.getViewPager().setCurrentItem(banner.getViewPager().getCurrentItem()-1);
banner.getViewPager().setCurrentItem(banner.getViewPager().getCurrentItem()+1);
}
});
}
},0);
<RadioGroup>
<RadioButton>
<RadioButton>
</RadioGroup>
radioGroup.setOnCheckedChangeListener(RadioGroup.OnCheckedChangeListener());
在adapter中
private View view;
@Override
//在方法会调用多次,第一次在onPageSelected前,所以可以使用该方法来在当前显示的视图进行一些操作
public void setPrimaryItem(ViewGroup container, int position, Object object) {
view= (View) object;
}
public View getPrimaryItem(){
return view;
}
getViewPager().addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
//该控件就是当前正在展示的子控件
View primaryItem = bannerAdapter.getPrimaryItem();
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
//也可以
View view =pagerAdapter.getView(viewpager, position);
//在第三方框架rollviewpager中需要
View view =pagerAdapter.getView(viewpager, position%getRealCount());
作用:
1.在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统的Service相同;
2.当任务执行完后,IntentService会自动停止,而不需要我们手动去控制或stopSelf();
3.可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService中执行;
public class MyIntentService extends IntentService {
//action
private static final String ACTION_FOO = "com.junx.nfc3.service.action.FOO";
private static final String ACTION_BAZ = "com.junx.nfc3.service.action.BAZ";
//用于获取参数的常量的key
private static final String EXTRA_PARAM1 = "com.junx.nfc3.service.extra.PARAM1";
private static final String EXTRA_PARAM2 = "com.junx.nfc3.service.extra.PARAM2";
public MyIntentService() {
super("MyIntentService");
}
//主要重写该方法即可
@Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
//先获取action,进行判断
final String action = intent.getAction();
if (ACTION_FOO.equals(action)) {
//获取参数,进行相应操作
final String param1 = intent.getStringExtra(EXTRA_PARAM1);
final String param2 = intent.getStringExtra(EXTRA_PARAM2);
handleActionFoo(param1, param2);
} else if (ACTION_BAZ.equals(action)) {
final String param1 = intent.getStringExtra(EXTRA_PARAM1);
final String param2 = intent.getStringExtra(EXTRA_PARAM2);
handleActionBaz(param1, param2);
}
}
}
//业务逻辑
private void handleActionFoo(String param1, String param2) {
// TODO: Handle action Foo
throw new UnsupportedOperationException("Not yet implemented");
}
private void handleActionBaz(String param1, String param2) {
// TODO: Handle action Baz
throw new UnsupportedOperationException("Not yet implemented");
}
//也可以写一个方法,给予act调用
public static void startSomeTask(Context context,String action,String params1,String params2){
Intent intent = new Intent(context,MyIntentService.class);
intent.setAction(action);
intent.putExtra(EXTRA_PARAM1,params1);
intent.putExtra(EXTRA_PARAM2,params2);
context.startService(intent);
}
}
bindService和startService的区别:
//生命周期
执行startService时,Service会经历onCreate->onStartCommand。当执行stopService时,直接调用onDestroy方法。调用者如果没有stopService,Service会一直在后台运行,下次调用者再起来仍然可以stopService;
执行bindService时,Service会经历onCreate->onBind。这个时候调用者和Service绑定在一起。调用者调用unbindService方法或者调用者Context不存在了(如Activity被finish了),Service就会调用onUnbind->onDestroy;
//多次调用时的区别
多次调用startService,该Service只能被创建一次,即该Service的onCreate方法只会被调用一次。但是每次调用startService,onStartCommand方法都会被调用。Service的onStart方法在API 5时被废弃,替代它的是onStartCommand方法;
第一次执行bindService时,onCreate和onBind方法会被调用,但是多次执行bindService时,onCreate和onBind方法并不会被多次调用,即并不会多次创建服务和绑定服务;
//后台判断最近是否打开了其他应用
public class MyService extends Service{
private LogBinder mLogBinder;
private static final int HAVE_BEEN_DESTROYED=-1;
@Override
public void onCreate() {
mLogBinder = new LogBinder();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mLogBinder;
}
//获取最近打开的包的应用的名字
public String getApplicationStatus() {
SystemClock.sleep(1000);
if (x!=0){
return "sdfs";
}
UsageStatsManager mUsageStatsManager = (UsageStatsManager)getApplicationContext().getSystemService(Context.USAGE_STATS_SERVICE);
long time = System.currentTimeMillis();
List<UsageStats> stats ;
stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time-60*60*1000, time);
if(stats != null) {
TreeMap<Long,UsageStats> mySortedMap = new TreeMap<Long,UsageStats>();
for (UsageStats usageStats : stats) {
mySortedMap.put(usageStats.getLastTimeUsed(),usageStats);
}
if(mySortedMap != null && !mySortedMap.isEmpty()) {
UsageStats usageStats = mySortedMap.get(mySortedMap.lastKey());
usageStats.getPackageName();
String packageName = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
return packageName;
}
}
return null;
}
Thread thread;
int x=0;
public class LogBinder extends Binder{
public void show(final CallBack callBack){
thread= new Thread(new Runnable() {
@Override
public void run() {
//当线程退出时终止循环
F:while(x!=HAVE_BEEN_DESTROYED){
String name = getApplicationStatus();
//如果最近打开的应用的包名不是以下的三个,则退出死循环
if (!name.equals("com.junx.mycircleview")&&!name.equals("com.android.launcher3")
&&!name.equals("com.android.systemui"))
break F;
}
if (x!=HAVE_BEEN_DESTROYED){
Log.v("meee","检测到打开了别的应用");
callBack.onShow("");
}
}
});
thread.start();
}
}
//监听数据回调
public interface CallBack{
void onShow(String text);
}
@Override
public void onDestroy() {
x=HAVE_BEEN_DESTROYED;
}
}
//实现ServiceConnection,用于获取binder对象
public class Myconn implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
((MyService.LogBinder) service).show(new MyService.CallBack() {
@Override
public void onShow(final String text) {
//当检测到打开其他应用后,执行相应操作
mHandler.sendEmptyMessage(233);
}
});
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
//绑定操作
intent = new Intent(this, MyService.class);
conn = new Myconn();
bindService(intent, conn, BIND_AUTO_CREATE);
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivity(intent);
在Setting中搜索Live Templates
选中android 点击右上方的+号
选择Live Template
输入缩写和完整内容后
记得在中下方选择applicable in Java
File dir = new File(Environment.getExternalStorageDirectory().getPath() + "/Pictures");
if (dir.exists()&&dir.isDirectory()){
long startTime = System.currentTimeMillis();
File[] files = dir.listFiles();
fore:for(File file:files){
if (file.length()>0&&file.getName().endsWith(".jpg")){
Log.d("TAG",getClass()+":\n"+"开始添加:"+file.toString());
Bitmap bitmap = BitmapFactory.decodeFile(file.toString());
//该方法在子线程运行,并在开始时会将Flag置false
processImg(bitmap,Uri.decode(file.toString()));
while(!Flag){
//循环等待
}
}
}
}
private void addPictures() {
AssetManager assetsManager = getAssets();
try {
String[] list = assetsManager.list("");
for (int i = 0; i < list.length; i++) {
String fileName=list[i];
if (!TextUtils.isEmpty(fileName)&&fileName.endsWith(".jpg")){
InputStream inputStream = assetsManager.open(fileName);
FileOutputStream fileOutputStream = new FileOutputStream(Environment.getExternalStorageDirectory().getPath()
+ "/picture/"+fileName);
byte[] b = new byte[1024];
int n=0;
while((n=inputStream.read(b))!=-1){
fileOutputStream.write(b, 0, n);
}
inputStream.close();
fileOutputStream.close();
Logger.d(""+fileName+">>>"+fileOutputStream);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
在module的gradle中
android {
...
sourceSets{
main{
jniLibs.srcDirs=['libs']
}
}
}
MediaStore.Images.Media.getBitmap(getApplicationContext().getContentResolver(),Uri.parse(max_id))
当该文件的目录不存在时,抛出异常;
当该文件不存在时,创建该文件,返回true
当该文件存在时,返回false
//在线程受到阻塞时抛出一个中断信号,这样线程就得以退出阻塞的状态.
//如果线程被Object.wait, Thread.join和Thread.sleep三种方法之一阻塞,那么,它将接收到一个中断异常(InterruptedException),从而提早地终结被阻塞状态。
调用线程的interrupt方法,并不能真正中断线程,只是给线程做了中断状态的标志
Thread.interrupted():测试当前线程是否处于中断状态。执行后将中断状态标志为false
Thread.isInterrupte(): 测试线程Thread对象是否已经处于中断状态。但不具有清除功能
AlertDialog.Builder builder = new AlertDialog.Builder(Videocmp.this);
builder.setTitle("请选择图片!");
builder.setItems(items, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int item) {
boolean result= Utility.checkPermission(Videocmp.this);
if (items[item].equals("拍照")) {
if(result)
cameraIntent();
} else if (items[item].equals("图库")) {
if(result)
galleryIntent();
} else if (items[item].equals("Cancel")) {
dialog.dismiss();
}
}
});
builder.show();
//保存时间做变量
Long mTime=System.currentTimeMills();
//前一天
mTime=mTime-(1000*60*60*24);
Bitmap bmp = Bitmap.createBitmap(150, 150, Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(bmp);
Paint paint = new Paint();
paint.setColor(Color.rgb(random.nextInt(128), random.nextInt(128), random.nextInt(128)));
paint.setTextSize(24);
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
canvas.drawRect(new Rect(0, 0, 150, 150), paint);
paint.setColor(Color.WHITE);
paint.setTextAlign(Paint.Align.CENTER);
canvas.drawText(s, 75, 75, paint);
//在listview或者gridview外部包装一层Scrollview的时候,需要动态设置设置listview的高度.使其处于内部item的与listview的高度相等
public class FixedViewUtil {
public static void setListViewHeightBasedOnChildren(GridView listView,int col) {
// 获取listview的adapter
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
return;
}
// 固定列宽,有多少列
int totalHeight = 0;
// i每次加4,相当于listAdapter.getCount()小于等于4时 循环一次,计算一次item的高度,
// listAdapter.getCount()小于等于8时计算两次高度相加
for (int i = 0; i < listAdapter.getCount(); i += col) {
// 获取listview的每一个item
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
// 获取item的高度和
totalHeight += listItem.getMeasuredHeight();
totalHeight += listView.getVerticalSpacing();
if (i==listAdapter.getCount()-1) {
totalHeight += listView.getVerticalSpacing();
}
}
// 获取listview的布局参数
ViewGroup.LayoutParams params = listView.getLayoutParams();
// 设置高度
params.height = totalHeight;
// 设置margin
((MarginLayoutParams) params).setMargins(10, 10, 10, 10);
// 设置参数
listView.setLayoutParams(params);
}
public static void setListViewHeightBasedOnChildren(ListView lv){
ListAdapter listAdapter = lv.getAdapter();
int listViewHeight = 0;
int adaptCount = listAdapter.getCount();
for(int i=0;i<adaptCount;i++){
View temp = listAdapter.getView(i,null,lv);
temp.measure(0,0);
listViewHeight += temp.getMeasuredHeight();
}
LayoutParams layoutParams = lv.getLayoutParams();
layoutParams.width = LayoutParams.MATCH_PARENT;
layoutParams.height = listViewHeight;
lv.setLayoutParams(layoutParams);
}
}
//也可以自定义gridview,使其占满最大
public class MyGridView extends GridView{
public MyGridView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyGridView(Context context) {
super(context);
}
public MyGridView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
// 方式一:new Dialog
final ProgressDialog dialog = new ProgressDialog(this);
dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);// 设置进度条的形式为圆形转动的进度条
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);// 设置水平进度条
dialog.show();
// 方式二:使用静态方式创建并显示,这种进度条只能是圆形条,设置title和Message提示内容
ProgressDialog dialog2 = ProgressDialog.show(this, "提示", "正在登陆中");
public static boolean firstDayIsBiggerOrEqualsSecond(String str1, String str2) {
boolean isBigger = false;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date dt1 = null;
Date dt2 = null;
try {
dt1 = sdf.parse(str1);
dt2 = sdf.parse(str2);
} catch (ParseException e) {
e.printStackTrace();
}
if (dt1.getTime() >= dt2.getTime()) {
isBigger = true;
} else if (dt1.getTime() < dt2.getTime()) {
isBigger = false;
}
return isBigger;
}
Calendar c = Calendar.getInstance();
c.setTimeZone(TimeZone.getTimeZone("GMT+8:00"));
int mCurrentDay=c.get(Calendar.DAY_OF_WEEK);
这个View有一个限制, 就是必须要在当前的View hierarchy里, 不然会不起作用.简单来说该view必须和listview在同一层中
public static void setEmptyView(ListView listview, View emptyView) {
FrameLayout emptyLayout;
if (listview.getEmptyView() == null) {
emptyLayout = new FrameLayout(listview.getContext());
emptyLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
emptyView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
emptyLayout.addView(emptyView);
emptyView.setVisibility(View.VISIBLE);
getParentView((ViewGroup) listview.getParent()).addView(emptyLayout);
listview.setEmptyView(emptyLayout);
} else {
emptyLayout = (FrameLayout) listview.getEmptyView();
emptyLayout.removeAllViews();
emptyLayout.setVisibility(View.VISIBLE);
emptyLayout.addView(emptyView);
}
}
private static ViewGroup getParentView(ViewGroup parent) {
ViewGroup tempVg = parent;
if (parent.getParent() != null && parent.getParent() instanceof ViewGroup) {
tempVg = (ViewGroup) parent.getParent();
getParentView(tempVg);
} else {
return tempVg;
}
return tempVg;
}
//依赖于手机系统,获取到的是系统的屏幕信息;
mDisplayMetrics = getResources().getDisplayMetrics();
//依赖于activity,获取到的是当前页面的屏幕的信息
WindowManager manager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
manager.getDefaultDisplay().getMetrics(dm);
1.
<activity android:name=".MainActivity" android:windowSoftInputMode="stateVisible|adjustPan">
2.在act的oncreate()
//需要在setContentView之前调用
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
setContentView(R.layout.activity_main);
3.
把顶级的layout替换成ScrollView,或者说在顶级的Layout上面再加一层ScrollView的封装。这样就会把软键盘和输入框一起滚动了,软键盘会一直处于底部。
api4.4以后,android便支持沉浸式
1.创建res/values-v19/style.xml文件
<resources>
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
<!--支持沉浸式效果-->
<item name="android:windowTranslucentStatus">true</item>
</style>
</resources>
2.通过反射获取状态栏的高度
public int getStatusHeight(Context context) {
int statusHeight = -1;
try {
Class clazz = Class.forName("com.android.internal.R$dimen");
Object object = clazz.newInstance();
int height = Integer.parseInt(clazz.getField("status_bar_height")
.get(object).toString());
statusHeight = context.getResources().getDimensionPixelSize(height);
} catch (Exception e) {
e.printStackTrace();
}
return statusHeight;
}
3.在布局文件的最上方设置一个imageview
//判断版本号,动态设置imageview高度和颜色
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.KITKAT){
int statusHeight = getStatusHeight(this);
ImageView iv2= (ImageView) findViewById(R.id.imageView2);
iv2.getLayoutParams().height=statusHeight;
iv2.setBackgroundColor(Color.RED);
}
FileOutputStream fileOutputStream = new FileOutputStream(Environment.getExternalStorageDirectory().getPath()
+ "/picture/TinyFile2Bitmap.jpg");
boolean isSuccessful = bitmap.compress(Bitmap.CompressFormat.JPEG, 20, fileOutputStream);
fileOutputStream.close();
android:letterSpacing="0.25" //以一个字的宽度做比例
[2017-10-13 09:51:45 - ddms] transfer error: No such file or directory
[2017-10-13 09:51:45] Failed to pull selection: No such file or directory
文件不要使用中文命名
View的机制决定了它无法通过getWidth获取宽高
但可以使用测量
获取测量宽高前需要先测量自身
sv.measure(0,0);
Log.v("meee",getClass()+":\n"+sv.getMeasuredHeight());
private void getPreViewImage() {
mCamera.setPreviewCallback(new Camera.PreviewCallback(){
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
Camera.Size size = camera.getParameters().getPreviewSize();
try{
YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
if(image!=null){
ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compressToJpeg(new Rect(0, 0, size.width, size.height), 80, stream);
Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
int i = bmp.getRowBytes() * bmp.getHeight() / 1024;
iv_student1.setImageBitmap(bmp);
stream.close();
mCamera.setPreviewCallback(null);
}
}catch(Exception ex){
Log.e("Sys","Error:"+ex.getMessage());
}
}
});
}
因为View中没有重写onmeasure方法,所以不支持wrap_content(效果为match_parent)
所以需要使用imageview做分割线,支持wrap_content
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
setTranslucentStatus(true);
}
tintManager = new SystemBarTintManager(this);
tintManager.setStatusBarTintEnabled(true);
tintManager.setStatusBarTintResource(android.R.color.transparent); //设置上方状态栏透明
}
@TargetApi(19)
private void setTranslucentStatus(boolean on) {
Window win = getWindow();
WindowManager.LayoutParams winParams = win.getAttributes();
final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
if (on) {
winParams.flags |= bits;
} else {
winParams.flags &= ~bits;
}
win.setAttributes(winParams);
}
mTabHost.getTabWidget().getChildTabViewAt(0).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
被fastjson的混淆坑伤了,决定用Gson:
#导包
compile 'com.google.code.gson:gson:2.8.2'
#转换
Model model = new Gson().fromJson(str, Model.class);
String jsonString = new Gson().toJson(model);//通过反射拿到的,没有get方法也可以
#属性转换
当后台返回的数据是这样的:{"address_detail":"333"}
但android的命名习惯是这样的
public class bean{
private String addressDetail;}
我们可以加上转化标签
public class bean{
@SerializedName("address_detail")
//@SerializedName(value = "emailAddress", alternate = {"email", "email_address"})
private String addressDetail;}
这样就可以解决前后台编码规范不同的问题啦,//但toJson的时候不会转换回来
#泛型的使用
很多时候,接口返回的json是这样的
{"code":"0","message":"success","data":[字段不同]}
如果我们解析字段是这样的
//每个接口都需要重写,很low
public class UserResponse {
public int code;
public String message;
public User data;
}
解决办法:
public class Result<T> {
public int code;
public String message;
public T data;
}
Model<List<ResultBean>> list = gson.fromJson(str
, new TypeToken<Model<List<ResultBean>>>() {//构造器是protect,只能以new xx(){}来创建
}.getType());
String fanxing = gson.toJson(list);//toJson支持泛型
public class Utils {
public static int dip2px(Context context, float dp) {
float scale = context.getResources().getDisplayMetrics().density;
return (int) (dp * scale + 0.5f);
}
}
一:在配置文件中修改
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.ct.parentipa"
android:versionCode="100107"
android:versionName="1.6.0">
二:在module的gradle中修改,优先级高于配置文件
android {
defaultConfig {
...
versionCode 1
versionName "1.0"
}
public static String getAppVersionName(Context context) {
String versionName = "";
int versioncode=0;
try {
// ---get the package info---
PackageManager pm = context.getPackageManager();
PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
versionName = pi.versionName;
versioncode = pi.versionCode;
if (versionName == null || versionName.length() <= 0) {
return "";
}
} catch (Exception e) {
}
return versionName;
}
private String getVersionName() throws Exception
{
// 获取packagemanager的实例
PackageManager packageManager = getPackageManager();
// getPackageName()是你当前类的包名,0代表是获取版本信息
PackageInfo packInfo = packageManager.getPackageInfo(getPackageName(),0);
String version = packInfo.versionName;
return version;
}
public class MD5 {
/**
* d41d8cd98f00b204e9800998ecf8427e MD5 ("a") =
* 0cc175b9c0f1b6a831c399e269772661 MD5 ("abc") =
* 900150983cd24fb0d6963f7d28e17f72 MD5 ("message digest") =
*/
public static String getMD5(byte[] source) {
String s = null;
char hexDigits[] = { // 用来将字节转换成 16 进制表示的字符组
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
try {
java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
md.update(source);
byte tmp[] = md.digest(); // MD5 的计算结果是128 位的长整数,
// 用字节表示就是 16 个字符
char str[] = new char[16 * 2]; // 每个字节都用 16 进制表示的话,使用两个字符,
int k = 0; // 表示转换结果中对应的字符位置
for (int i = 0; i < 16; i++) {
byte byte0 = tmp[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
s = new String(str);
} catch (Exception e) {
e.printStackTrace();
}
return s;
}
static final int S11 = 7;
static final int S12 = 12;
static final int S13 = 17;
static final int S14 = 22;
static final int S21 = 5;
static final int S22 = 9;
static final int S23 = 14;
static final int S24 = 20;
static final int S31 = 4;
static final int S32 = 11;
static final int S33 = 16;
static final int S34 = 23;
static final int S41 = 6;
static final int S42 = 10;
static final int S43 = 15;
static final int S44 = 21;
static final byte[] PADDING = { -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 };
private long[] state = new long[4];
private long[] count = new long[2];
private byte[] buffer = new byte[64];
public String digestHexStr;
private byte[] digest = new byte[16];
public String getMD5ofStr(String inbuf) {
md5Init();
md5Update(inbuf.getBytes(), inbuf.length());
md5Final();
digestHexStr = "";
for (int i = 0; i < 16; i++) {
digestHexStr += byteHEX(digest[i]);
}
return digestHexStr;
}
public MD5() {
md5Init();
return;
}
private void md5Init() {
count[0] = 0L;
count[1] = 0L;
state[0] = 0x67452301L;
state[1] = 0xefcdab89L;
state[2] = 0x98badcfeL;
state[3] = 0x10325476L;
return;
}
private long F(long x, long y, long z) {
return (x & y) | ((~x) & z);
}
private long G(long x, long y, long z) {
return (x & z) | (y & (~z));
}
private long H(long x, long y, long z) {
return x ^ y ^ z;
}
private long I(long x, long y, long z) {
return y ^ (x | (~z));
}
private long FF(long a, long b, long c, long d, long x, long s, long ac) {
a += F(b, c, d) + x + ac;
a = ((int) a << s) | ((int) a >>> (32 - s));
a += b;
return a;
}
private long GG(long a, long b, long c, long d, long x, long s, long ac) {
a += G(b, c, d) + x + ac;
a = ((int) a << s) | ((int) a >>> (32 - s));
a += b;
return a;
}
private long HH(long a, long b, long c, long d, long x, long s, long ac) {
a += H(b, c, d) + x + ac;
a = ((int) a << s) | ((int) a >>> (32 - s));
a += b;
return a;
}
private long II(long a, long b, long c, long d, long x, long s, long ac) {
a += I(b, c, d) + x + ac;
a = ((int) a << s) | ((int) a >>> (32 - s));
a += b;
return a;
}
private void md5Update(byte[] inbuf, int inputLen) {
int i, index, partLen;
byte[] block = new byte[64];
index = (int) (count[0] >>> 3) & 0x3F;
if ((count[0] += (inputLen << 3)) < (inputLen << 3))
count[1]++;
count[1] += (inputLen >>> 29);
partLen = 64 - index;
if (inputLen >= partLen) {
md5Memcpy(buffer, inbuf, index, 0, partLen);
md5Transform(buffer);
for (i = partLen; i + 63 < inputLen; i += 64) {
md5Memcpy(block, inbuf, 0, i, 64);
md5Transform(block);
}
index = 0;
} else
i = 0;
md5Memcpy(buffer, inbuf, index, i, inputLen - i);
}
private void md5Final() {
byte[] bits = new byte[8];
int index, padLen;
Encode(bits, count, 8);
index = (int) (count[0] >>> 3) & 0x3f;
padLen = (index < 56) ? (56 - index) : (120 - index);
md5Update(PADDING, padLen);
md5Update(bits, 8);
Encode(digest, state, 16);
}
private void md5Memcpy(byte[] output, byte[] input, int outpos, int inpos, int len) {
int i;
for (i = 0; i < len; i++)
output[outpos + i] = input[inpos + i];
}
private void md5Transform(byte block[]) {
long a = state[0], b = state[1], c = state[2], d = state[3];
long[] x = new long[16];
Decode(x, block, 64);
a = FF(a, b, c, d, x[0], S11, 0xd76aa478L); /* 1 */
d = FF(d, a, b, c, x[1], S12, 0xe8c7b756L); /* 2 */
c = FF(c, d, a, b, x[2], S13, 0x242070dbL); /* 3 */
b = FF(b, c, d, a, x[3], S14, 0xc1bdceeeL); /* 4 */
a = FF(a, b, c, d, x[4], S11, 0xf57c0fafL); /* 5 */
d = FF(d, a, b, c, x[5], S12, 0x4787c62aL); /* 6 */
c = FF(c, d, a, b, x[6], S13, 0xa8304613L); /* 7 */
b = FF(b, c, d, a, x[7], S14, 0xfd469501L); /* 8 */
a = FF(a, b, c, d, x[8], S11, 0x698098d8L); /* 9 */
d = FF(d, a, b, c, x[9], S12, 0x8b44f7afL); /* 10 */
c = FF(c, d, a, b, x[10], S13, 0xffff5bb1L); /* 11 */
b = FF(b, c, d, a, x[11], S14, 0x895cd7beL); /* 12 */
a = FF(a, b, c, d, x[12], S11, 0x6b901122L); /* 13 */
d = FF(d, a, b, c, x[13], S12, 0xfd987193L); /* 14 */
c = FF(c, d, a, b, x[14], S13, 0xa679438eL); /* 15 */
b = FF(b, c, d, a, x[15], S14, 0x49b40821L); /* 16 */
a = GG(a, b, c, d, x[1], S21, 0xf61e2562L); /* 17 */
d = GG(d, a, b, c, x[6], S22, 0xc040b340L); /* 18 */
c = GG(c, d, a, b, x[11], S23, 0x265e5a51L); /* 19 */
b = GG(b, c, d, a, x[0], S24, 0xe9b6c7aaL); /* 20 */
a = GG(a, b, c, d, x[5], S21, 0xd62f105dL); /* 21 */
d = GG(d, a, b, c, x[10], S22, 0x2441453L); /* 22 */
c = GG(c, d, a, b, x[15], S23, 0xd8a1e681L); /* 23 */
b = GG(b, c, d, a, x[4], S24, 0xe7d3fbc8L); /* 24 */
a = GG(a, b, c, d, x[9], S21, 0x21e1cde6L); /* 25 */
d = GG(d, a, b, c, x[14], S22, 0xc33707d6L); /* 26 */
c = GG(c, d, a, b, x[3], S23, 0xf4d50d87L); /* 27 */
b = GG(b, c, d, a, x[8], S24, 0x455a14edL); /* 28 */
a = GG(a, b, c, d, x[13], S21, 0xa9e3e905L); /* 29 */
d = GG(d, a, b, c, x[2], S22, 0xfcefa3f8L); /* 30 */
c = GG(c, d, a, b, x[7], S23, 0x676f02d9L); /* 31 */
b = GG(b, c, d, a, x[12], S24, 0x8d2a4c8aL); /* 32 */
a = HH(a, b, c, d, x[5], S31, 0xfffa3942L); /* 33 */
d = HH(d, a, b, c, x[8], S32, 0x8771f681L); /* 34 */
c = HH(c, d, a, b, x[11], S33, 0x6d9d6122L); /* 35 */
b = HH(b, c, d, a, x[14], S34, 0xfde5380cL); /* 36 */
a = HH(a, b, c, d, x[1], S31, 0xa4beea44L); /* 37 */
d = HH(d, a, b, c, x[4], S32, 0x4bdecfa9L); /* 38 */
c = HH(c, d, a, b, x[7], S33, 0xf6bb4b60L); /* 39 */
b = HH(b, c, d, a, x[10], S34, 0xbebfbc70L); /* 40 */
a = HH(a, b, c, d, x[13], S31, 0x289b7ec6L); /* 41 */
d = HH(d, a, b, c, x[0], S32, 0xeaa127faL); /* 42 */
c = HH(c, d, a, b, x[3], S33, 0xd4ef3085L); /* 43 */
b = HH(b, c, d, a, x[6], S34, 0x4881d05L); /* 44 */
a = HH(a, b, c, d, x[9], S31, 0xd9d4d039L); /* 45 */
d = HH(d, a, b, c, x[12], S32, 0xe6db99e5L); /* 46 */
c = HH(c, d, a, b, x[15], S33, 0x1fa27cf8L); /* 47 */
b = HH(b, c, d, a, x[2], S34, 0xc4ac5665L); /* 48 */
a = II(a, b, c, d, x[0], S41, 0xf4292244L); /* 49 */
d = II(d, a, b, c, x[7], S42, 0x432aff97L); /* 50 */
c = II(c, d, a, b, x[14], S43, 0xab9423a7L); /* 51 */
b = II(b, c, d, a, x[5], S44, 0xfc93a039L); /* 52 */
a = II(a, b, c, d, x[12], S41, 0x655b59c3L); /* 53 */
d = II(d, a, b, c, x[3], S42, 0x8f0ccc92L); /* 54 */
c = II(c, d, a, b, x[10], S43, 0xffeff47dL); /* 55 */
b = II(b, c, d, a, x[1], S44, 0x85845dd1L); /* 56 */
a = II(a, b, c, d, x[8], S41, 0x6fa87e4fL); /* 57 */
d = II(d, a, b, c, x[15], S42, 0xfe2ce6e0L); /* 58 */
c = II(c, d, a, b, x[6], S43, 0xa3014314L); /* 59 */
b = II(b, c, d, a, x[13], S44, 0x4e0811a1L); /* 60 */
a = II(a, b, c, d, x[4], S41, 0xf7537e82L); /* 61 */
d = II(d, a, b, c, x[11], S42, 0xbd3af235L); /* 62 */
c = II(c, d, a, b, x[2], S43, 0x2ad7d2bbL); /* 63 */
b = II(b, c, d, a, x[9], S44, 0xeb86d391L); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
}
private void Encode(byte[] output, long[] input, int len) {
int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (byte) (input[i] & 0xffL);
output[j + 1] = (byte) ((input[i] >>> 8) & 0xffL);
output[j + 2] = (byte) ((input[i] >>> 16) & 0xffL);
output[j + 3] = (byte) ((input[i] >>> 24) & 0xffL);
}
}
private void Decode(long[] output, byte[] input, int len) {
int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = b2iu(input[j]) | (b2iu(input[j + 1]) << 8) | (b2iu(input[j + 2]) << 16)
| (b2iu(input[j + 3]) << 24);
return;
}
public static long b2iu(byte b) {
return b < 0 ? b & 0x7F + 128 : b;
}
public static String byteHEX(byte ib) {
char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
char[] ob = new char[2];
ob[0] = Digit[(ib >>> 4) & 0X0F];
ob[1] = Digit[ib & 0X0F];
String s = new String(ob);
return s;
}
public static void main(String argv[]) {
System.out.println(MD5.getMD5("123".getBytes()));
}
}
//data转换为时间戳
public static String dateToStamp(String s) throws ParseException{
String res;
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = simpleDateFormat.parse(s);
long ts = date.getTime();
res = String.valueOf(ts);
return res;
}
//时间戳转换为时间
public static String stampToDate(String s){
String res;
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
long lt = new Long(s);
Date date = new Date(lt);
res = simpleDateFormat.format(date);
return res;
}
JSONObject jsonObject = new JSONObject(k);
status = jsonObject.getInt("status");
JSONArray jsonArray = jsonObject.getJSONArray("datas");
object = jsonArray.get(i);
每次请求发现过期,但在过期时进行递归回调发现偶尔又能成功
最后发现是登陆时使用的sss.com的域名 请求时是使用的192.域名,
最后造成了这个状况
//设置提示框的宽高
Window dialogWindow = dialog.getWindow();
WindowManager m = getActivity().getWindowManager();
Display d = m.getDefaultDisplay(); // 获取屏幕宽、高用
WindowManager.LayoutParams p = dialogWindow.getAttributes(); // 获取对话框当前的参数值
p.height = (int) (d.getHeight() * 0.3); // 高度设置为屏幕的0.6
p.width = (int) (d.getWidth() * 0.8); // 宽度设置为屏幕的0.65
dialogWindow.setAttributes(p);
第一次加载Fragment时,给EditText赋值后,remove后,重新加载这个Fragment,并且给EditText重新赋值,可是页面上显示EditText仍然为原来的值。
原因:
当fragment已存在时,重新加载会执行onViewStateRestored把原有的控件数据重新赋值回来。onViewStateRestored在onActivityCreated(Bundle)后面执行,所以onViewCreated里面的mobileEt被覆盖掉了。
解决办法,重写onViewStateRestored
@Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
mobileEt.setText(mobile);
}
1.但在线性布局使用很合适,其他很难说
使用RecyclerView.OnScrollListener来监听RecyclerView判断上拉的时候是否滑动到底部,然后实现加载逻辑
2.三方:HeaderViewRecyclerAdapter
如果item的根布局使用了linearlayout,framelayout会出现宽高都为wrap_content的问题
解决:
在adapter中,
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//第一 二种inflate方式都不行
View.inflate(parent.getContext(),R.layout.item_msg_chat,null);
LayoutInflater.from(parent.getContext()).inflate(R.layout.item_msg_chat,null);
//这种才不会有这种奇怪的情况
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_msg_chat, parent, false);
return new ViewHolder(view);
}
<TextView
android:maxWidth="300dp"
android:singleLine="false"
//旋转图片的方向
public static Bitmap rotateBitmapByDegree(Bitmap bm, int degree) {
Bitmap returnBm = null;
Matrix matrix = new Matrix();
matrix.postRotate(degree);
try {
returnBm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(),
bm.getHeight(), matrix, true);
} catch (OutOfMemoryError e) {
}
if (returnBm == null) {
returnBm = bm;
}
if (bm != returnBm) {
bm.recycle();
}
return returnBm;
}
权限:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
receiver:
public class NetWorkStatusReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
Toast.makeText(context, "network changed:"+getConnectedType(context), Toast.LENGTH_LONG).show();
}
}
public int getConnectedType(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
if (mNetworkInfo != null && mNetworkInfo.isAvailable()) {
return mNetworkInfo.getType();
}
}
return -1;
}
}
注册:
//通过广播监控网络状态
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(new NetWorkStatusReceiver(),intentFilter);
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
public boolean isNetworkConnected(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
if (mNetworkInfo != null) {
return mNetworkInfo.isAvailable();
}
}
return false;
}
//获取网络类型
public static final int TYPE_NOT_NET=0;
public static final int TYPE_WIFI = 1;
public static final int TYPE_MOBILE_MMS = 2;
public static final int TYPE_MOBILE_SUPL = 3;
public static final int TYPE_MOBILE_DUN = 4;
public static final int TYPE_MOBILE_HIPRI = 5;
public static final int TYPE_WIMAX = 6;
public static final int TYPE_BLUETOOTH = 7;
public static final int TYPE_DUMMY = 8;
public static final int TYPE_ETHERNET = 9;
public static final int TYPE_MOBILE_FOTA = 10;
public static final int TYPE_MOBILE_IMS = 11;
public static final int TYPE_MOBILE_CBS = 12;
public static final int TYPE_WIFI_P2P = 13;
public static final int TYPE_MOBILE_IA = 14;
public static final int TYPE_MOBILE_EMERGENCY = 15;
public static final int TYPE_PROXY = 16;
public static final int TYPE_VPN = 17;
public int getConnectedType(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
if (mNetworkInfo != null && mNetworkInfo.isAvailable()) {
return mNetworkInfo.getType();
}
}
return -1;
}
//清空指定任务
mHandler.removeMessages(12);
//清空所有任务
mHandler.removeCallbacksAndMessages(null);
1.
String tabs[] = new String[]{"家长留言", "上课打卡", "主页", "校园信箱"};
2.
for (int i = 0; i < tabs.length; i++) {
//在这里传入的值就是tag
TabHost.TabSpec tabSpec = mTabHost.newTabSpec(tabs[i]);
tabSpec.setIndicator(getView(i));
mTabHost.addTab(tabSpec, classes[i], null);
}
3.可以通过fragmentmanager的findFragmentByTag(String tag)来获取fragmeng实例
ItemFragment2 fragment = (ItemFragment2) mManager.findFragmentByTag("上课打卡");
/mnt/sdcard/Pictures/20170921-10:46:08.png: open failed: EINVAL (Invalid argument)
保存失败,发现保存时图片中不能带有:号
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- 圆角 -->
<corners
android:radius="9dp"
android:topLeftRadius="2dp"
android:topRightRadius="2dp"
android:bottomLeftRadius="2dp"
android:bottomRightRadius="2dp"/><!-- 设置圆角半径 -->
<!-- 渐变 -->
<gradient
android:startColor="@android:color/white"
android:centerColor="@android:color/black"
android:endColor="@android:color/black"
android:useLevel="true"
android:angle="45"
android:type="radial"
android:centerX="0"
android:centerY="0"
android:gradientRadius="90"/>
<!-- 间隔 -->
<padding
android:left="2dp"
android:top="2dp"
android:right="2dp"
android:bottom="2dp"/><!-- 各方向的间隔 -->
<!-- 大小 -->
<size
android:width="50dp"
android:height="50dp"/><!-- 宽度和高度 -->
<!-- 填充 -->
<solid
android:color="@android:color/white"/><!-- 填充的颜色 -->
<!-- 描边 -->
<stroke
android:width="2dp"
android:color="@android:color/black"
android:dashWidth="1dp"
android:dashGap="2dp"/>
</shape>
填充:设置填充的颜色
间隔:设置四个方向上的间隔
大小:设置大小
圆角:同时设置五个属性,则Radius属性无效
android:Radius="20dp" 设置四个角的半径
android:topLeftRadius="20dp" 设置左上角的半径
android:topRightRadius="20dp" 设置右上角的半径
android:bottomLeftRadius="20dp" 设置右下角的半径
android:bottomRightRadius="20dp" 设置左下角的半径
描边:dashWidth和dashGap属性,只要其中一个设置为0dp,则边框为实现边框
android:width="20dp" 设置边边的宽度
android:color="@android:color/black" 设置边边的颜色
android:dashWidth="2dp" 设置虚线的宽度
android:dashGap="20dp" 设置虚线的间隔宽度
渐变:当设置填充颜色后,无渐变效果。angle的值必须是45的倍数(包括0),仅在type="linear"有效,
handler.sendEmptyMessageDelayed(MESSAGE_LOGIN,5000);
handler.removeMessages(MESSAGE_LOGIN);
public class SettingPop extends AlertDialog{
protected SettingPop(@NonNull Context context) {
super(context);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pop_setting);
//解决alertdialog不能弹出输入法的问题
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
|WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
}
}
右键一张png图片,Create 9Patch file
双击生成的9.图,选择拉伸区域
注:9.必须放在drawable目录下,否则报错
后缀必须为.9.png
左上为拉伸区域,右下为文字显示区域
1.将类库导入到adt中
import project
2.添加类库作为依赖
右键project
properties
Android>>library>>add apply
下载到compat包
复制到lib下...就是这么简单
右键project
properties
修改编码格式,一般是UTF-8 GBK
将错误提示滚动到最后
点击Enable support
会弹出是否restart 点击是等待其重启启动后即可
从Eclipse中导出
1.将你的ADT插件版本升级到22.0以上。
2.在Eclipse中,选择File-->Export。
3.在弹出的导出窗口中,打开Android的文件夹,选择“Generate Gradle Build Files”。
4.选中你想要导入到Android Studio中的项目,Finish。
PS:导出的项目将会和原来的项目在同一目录,覆盖原来的同时,会新增一个叫build.gradle的文件,导入Android Studio时将首先读取这个文件。
导入到Android Studio
1.在Android Studio 中,首先关掉你当前的打开的项目。
2.在欢迎界面,点击Import Project(注:也是可以直接在菜单选择Import project的)
3.选中你在Eclipse中导出的项目,展开目录,点击build.gradle文件,然后OK
4.在之后的弹出对话框中,会要求你选择Gradle的配置,选中Use gradle wrapper.(注:也可以自定义你本机装的Gradle)
右键project Android Tools
Export Singed Apk
选择要生成apk的project
输入两次密码
wrap_content即可
api23后,google移除了某些类
可以通过导入jar包的方式解决
一般是由于编码格式错误引起的
可以在module 的gradle中修改
android {
compileSdkVersion 26
buildToolsVersion "25.0.3"
android {compileOptions.encoding = "gbk"}//添加这一行,强制运行时的编码格式
但设置修改的编码格式是全局的
也可以修改某一个文件的编码格式
在android studio的右下角,可以设置编码格式
CRLF>>relode 是以不同的编码格式重新打开 convert:是以当前的文本更改代码格式为选中的编码格式
为该Fragment提供一个默认的空构造器
@SuppressLint("ResourceAsColor,ValidFragment")
意思是应该使用bundle来传递函数
可以使用两种方法解决
1.修改形参,使用bundle传递数据
2.添加注解
@SuppressLint("ValidFragment")
public class PhotoFragment extends MyBaseFragment {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");//2017-08-28
Date date = new Date();//当前时间
String dateStr = format.format(date);
08-28 03:00:04.087 11104-11104/com.ct.teacheripa V/meee: school_id=41010004
08-28 03:00:04.087 11104-11104/com.ct.teacheripa V/meee: type=1
08-28 03:00:04.087 11104-11104/com.ct.teacheripa V/meee: date=2017-08-28
08-28 03:00:04.087 11104-11104/com.ct.teacheripa V/meee: login_name=410100045001
08-28 03:00:04.087 11104-11104/com.ct.teacheripa V/meee: class_id=41010004G55C0
08-28 03:00:04.087 11104-11104/com.ct.teacheripa V/meee: school_id=41010004
生成签名的apk
build >generate Signed Apk>输入两次密码
基本混淆模版
在module的build.gradle
android {
......
buildTypes {
release {
//开启混淆
minifyEnabled true
// Zipalign优化
zipAlignEnabled true
// 移除无用的resource文件
shrinkResources true
//第一个是系统默认的基本混淆,第二个是自定义的混淆PLUS
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}
proguard-rules.pro模版
#############################################
#
# 对于一些基本指令的添加
#
#############################################
# 代码混淆压缩比,在0~7之间,默认为5,一般不做修改
-optimizationpasses 5
# 混合时不使用大小写混合,混合后的类名为小写
-dontusemixedcaseclassnames
# 指定不去忽略非公共库的类
-dontskipnonpubliclibraryclasses
# 这句话能够使我们的项目混淆后产生映射文件
# 包含有类名->混淆后类名的映射关系
-verbose
# 指定不去忽略非公共库的类成员
-dontskipnonpubliclibraryclassmembers
# 不做预校验,preverify是proguard的四个步骤之一,Android不需要preverify,去掉这一步能够加快混淆速度。
-dontpreverify
# 保留Annotation不混淆
-keepattributes *Annotation*,InnerClasses
# 避免混淆泛型
-keepattributes Signature
# 抛出异常时保留代码行号
-keepattributes SourceFile,LineNumberTable
# 指定混淆是采用的算法,后面的参数是一个过滤器
# 这个过滤器是谷歌推荐的算法,一般不做更改
-optimizations !code/simplification/cast,!field/*,!class/merging/*
#############################################
#
# Android开发中一些需要保留的公共部分
#
#############################################
# 保留我们使用的四大组件,自定义的Application等等这些类不被混淆
# 因为这些子类都有可能被外部调用
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Appliction
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.view.View
-keep public class com.android.vending.licensing.ILicensingService
# 保留support下的所有类及其内部类
-keep class android.support.** {*;}
# 保留继承的
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**
# 保留R下面的资源
-keep class **.R$* {*;}
# 保留本地native方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}
# 保留在Activity中的方法参数是view的方法,
# 这样以来我们在layout中写的onClick就不会被影响
-keepclassmembers class * extends android.app.Activity{
public void *(android.view.View);
}
# 保留枚举类不被混淆
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# 保留我们自定义控件(继承自View)不被混淆
-keep public class * extends android.view.View{
*** get*();
void set*(***);
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
# 保留Parcelable序列化类不被混淆
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
# 保留Serializable序列化的类不被混淆
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
!private <fields>;
!private <methods>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
# 对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆
-keepclassmembers class * {
void *(**On*Event);
void *(**On*Listener);
}
# webView处理,项目中没有使用到webView忽略即可
-keepclassmembers class fqcn.of.javascript.interface.for.webview {
public *;
}
-keepclassmembers class * extends android.webkit.webViewClient {
public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
public boolean *(android.webkit.WebView, java.lang.String);
}
-keepclassmembers class * extends android.webkit.webViewClient {
public void *(android.webkit.webView, jav.lang.String);
}
对于有些旧版本的项目并没有proguard-rules.pro,stackoverflow中有解答
Looks like your project is missing proguard files. You can add it yourself: put the proguard-rules.txt file into the app directory. It's already added to your build.gradle file so no further actions required.
shareimprove this answer
answered Jul 29 '15 at 9:52
aga
17.3k75079
3
Android Studio older version do not include proguard-rules.pro automatically, so manually adding it works...Thank you !! – Kushal Jul 29 '15 at 13:14
Android Studio关联SVN
只有安装了command line的svn可以关联as(默认不安装)
在安装svn配置选项中选择command line>>will be installed
在as中的setting >>subversion >>general>>use command line>>右边的三个点 >>找到svn.exe
忽略某些代码
Settings->Version Control>>右边的+号
一一般需要忽略.idea文件夹、.gradle文件夹、所有的build文件夹、所有的.iml文件及local.properties文件。
忽略完文件后,我们进行项目同SVN的关联,选择VCS->Import into Version Control->Share Project(Subversion);
这里说明一点,在Import into Version Control下有Import into Subversion和Share Project(Subversion)两个选项;第一个是直接将项目导入到SVN服务器上,但是这样做本地的项目同SVN服务器没有建立起关联,在导入后项目所有的文件都会变成红色,而且在要提交到SVN服务器时会提示项目不是SVN下的工作副本;第二个是将Android Studio当前项目同SVN服务器关联起来,但是并没有将项目导入到SVN服务器上,需要在完成建立连接后再次提交项目到SVN服务器。
svn和as关联简易使用说明
http://www.it165.net/pro/html/201508/51801.html
是一款控件级别的图片加载框架
//导包
compile 'com.facebook.fresco:fresco:1.5.0'
//使用方法
使用时,将显示显示图片的ImageView更改为SimpleDraweeView即可
在代码中指定图片的uri
Uri uri=Uri.parse("http://sfsf.com/a.png")
draweeView.setImageURI(uri);
//原理:
三级缓存,除内存外的缓存处理在非ui线程;
一.Bitmap缓存
1.bitmap缓存,5.0版本以后bmp缓存位于java的堆head中
4.x及以前是位于ashmem中,而不是在java的堆内存中,这意味着图片的创建和回收不会引发过多的GC
当app切换到后台时,bitmap缓存会被回收
二.内存缓存
内存缓存中存储了图片的原始压缩格式,从内存缓存中去取出的图片,在显示之前必须先解码,当后台时,内存缓存也会被清空
三.磁盘缓存
存储的也是图片的原始压缩格式,在使用前也要进行解码,即使关机磁盘缓存也不会丢失
优化效果:ram :180m>>80m
有3个线程池:
1.3个线程用于网路下载图片
2.2个线程用于磁盘文件的读写
3.2个线程用于CPU的相关操作,比如图片的解码,转换,以后后台的一些耗时操作
使用fiddler发现,该请求不带cookies
原因:
1.使用的是第三方的网路请求框架
如果请求的框架的对象不同,那么便不带cookies
2.后来还发现可能是模拟器的时间没有校准
解决办法:使用单例模式来封装请求框架,校准
按照生命周期依次读一遍,尽量弄懂每个方法的意思,再阅读点击事件
然后再读一遍
compile 'com.squareup.picasso:picasso:2.5.2'
//展示默认
Picasso.with(this).load(imageUrl).placeholder(R.mipmap.default_image).into(imageView);
//请求错误时候
Picasso.with(this).load(imageUrl+"landptf").error(R.mipmap.default_image).into(imageView);
//图片填充方式
Picasso.with(this).load(imageUrl).fit().into(imageView);
//旋转图片
//以(0,0)为中心顺时针旋转45度
Picasso.with(this).load(imageUrl).rotate(45).into(imageView);
//以(64,64)为中心顺时针旋转45度
Picasso.with(this).load(imageUrl).rotate(45, 64, 64).into(imageView);
1.获取fiddler的端口号
Tool>>Fiddler Options>>connections
2.获取本地的ip地址
alt+r>>cmd>>ipconfig
3.在模拟器中网络 >>详细设置中设置ip和端口号
注意如果fiddler没有打开||本地模拟器改变,那么模拟器是无法上网的,所用用完要把模拟器设置回去
绿色,已经加入控制暂未提交
红色,未加入版本控制
蓝色,加入,已提交,有改动
白色,加入,已提交,无改动
灰色:版本控制已忽略文件。
Setttings>>Live Templates
选中android
就可以自定义自己的代码模版了
1.导包
repositories {
mavenCentral()
}
dependencies {
compile 'com.loopj.android:android-async-http:1.4.9'
}
2.post请求使用方法
public class AsyncHttpAsynchttpUtil {
//final单例模式,让请求带上cookies
static final AsyncHttpClient client = new AsyncHttpClient();
public static void loadSchoolBuspisition(String url,
String value, final OnLodaSchoolbusPisition loadListener){
//设置post的请求参数
RequestParams params = new RequestParams();
params.put("key", value);
//使用client的post()发起请求,并使用接口进行回调
client.post(url, params, new AsyncHttpResponseHandler() {
@Override
public void onFailure(int arg0, Header[] arg1, byte[] arg2,
Throwable arg3) {
//arg0是响应码
}
@Override
public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {
//arg2是数据流
String result = new String(arg2);
//通过接口进行回调
loadListener.OnFinish(list, status);
}
});
}
}
github:
https://github.com/sephiroth74/ImageViewZoom
1.导包
gradle:
compile 'it.sephiroth.android.library.imagezoom:imagezoom:+'
2.使用方法
setImageBitmap( final Bitmap bitmap, Matrix matrix );
setImageBitmap( final Bitmap bitmap, Matrix matrix, float minZoom, float maxZoom );
如果你想加载一张新的bmp(the same from another ImageView ),你可以使用
Matrix matrix = mImageView1.getDisplayMatrix();
mImageView2.setImageBitmap( bitmap, matrix);
//获取屏幕的宽高
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
widths = dm.widthPixels;
heights = dm.heightPixels;
//获取图片的参数
bitmap = BitmapFactory.decodeByteArray(datas, 0, datas.length, options);
Bitmap BitmapOrg = bitmap;
int width = BitmapOrg.getWidth();
int height = BitmapOrg.getHeight();
//目标宽高为屏幕的宽高
int newWidth = widths;
int newHeight = heights;
//当前宽高和屏幕宽高的比例
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
//取较小值
float bls = scaleWidth < scaleHeight ? scaleWidth : scaleHeight;
Matrix matrix = new Matrix();
matrix.postScale(bls, bls);
bitmap = Bitmap.createBitmap(BitmapOrg, 0, 0, width, height, matrix, true);
private Bitmap yasuo(String filePath) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
// 获取这个图片的宽和高
BitmapFactory.decodeFile(filePath, options); //此时返回bm为空
//设置缩放比
options.inSampleSize = 2;
//重新读入图片,注意这次要把options.inJustDecodeBounds 设为 false哦
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);
return bitmap;
}
//保存图片至本地
public static void saveImageToGallery(Context context, Bitmap bmp) {
if (bmp==null){
Toast.makeText(context,"保存图片失败",Toast.LENGTH_SHORT).show();
return;
}
// 首先保存图片
File appDir = new File(Environment.getExternalStorageDirectory(), "Boohee");
if (!appDir.exists()) {
appDir.mkdir();
}
String fileName = System.currentTimeMillis() + ".jpg";
File file = new File(appDir, fileName);
try {
FileOutputStream fos = new FileOutputStream(file);
bmp.compress(CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// 其次把文件插入到系统图库
try {
MediaStore.Images.Media.insertImage(context.getContentResolver(),
file.getAbsolutePath(), fileName, null);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
//解决在部分机器缓存更新不及时问题
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Intent mediaScanIntent = new Intent(
Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri contentUri = Uri.fromFile(file); //out is your output file
mediaScanIntent.setData(contentUri);
context.sendBroadcast(mediaScanIntent);
} else {
context.sendBroadcast(new Intent(
Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://" + Environment.getExternalStorageDirectory())));
}
Toast.makeText(context, "保存成功", 1).show();
}
marginTop和marginBottom的问题
当两个相冲突的时候,不确定哪个发生作用
特别注意两个控件的margin相冲的时候
图片质量压缩:
OutputStream outputStream = new ByteArrayOutputStream();
//质量为0-100之间
BitmapFactory.decodeResource(res, R.drawable.studentdefault).compress(Bitmap.CompressFormat.JPEG,100,outputStream);
byte[] bytes = outputStream.toString().getBytes();
bitmap = BitmapFactory.decodeByteArray(bytes,0,bytes.length);
viewHolder.logo.setImageBitmap(bitmap);
//仅仅是改变图片的质量,但所占内存大小不变,改变的是该图片的文件占用大小
采样压缩:
BitmapFactory.Options options = new BitmapFactory.Options();
//采样率为2,间隔两个像素才采集一次像素,宽高都为原来的一半
options.inSampleSize = 2;
bitmap=BitmapFactory.decodeResource(res, R.drawable.studentdefault);
参数矩阵压缩:(这个效果好)
bitmap= BitmapFactory.decodeResource(res,R.drawable.studentdefault);
Matrix matrix = new Matrix();
matrix.setScale(0.3f,0.3f); bitmap=Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true);
边界压缩:
private Bitmap getImage() {
BitmapFactory.Options newOpts = new BitmapFactory.Options();
newOpts.inJustDecodeBounds = false;
newOpts.inSampleSize = 2;//设置缩放比例
//重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
Bitmap bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.flash, newOpts);
return bitmap;//压缩好比例大小后再进行质量压缩
}
压缩到自定义的大小
public Bitmap createBitmapThumbnail(Bitmap bitMap,int newWidth,int newHeight) {
int width = bitMap.getWidth();
int height = bitMap.getHeight();
// 计算缩放比例
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// 取得想要缩放的matrix参数
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
// 得到新的图片
Bitmap newBitMap = Bitmap.createBitmap(bitMap, 0, 0, width, height,
matrix, true);
return newBitMap;
}
//只需要遍历一次
Iterator iterator = map.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry entry = (Map.Entry) iterator.next();
String key = (String) entry.getKey();
String value = (String) entry.getValue();
}
//效率比较低,需要遍历两次
Iterator iterator = map.keySet().iterator();
while(iterator.hasNext()){
Object key = iterator.next();
Object o = map.get(key);
}
有个坑,如果fragment的oncreatview的中inflater生成的view与父控件绑定的话,会oom
androidstudio怎么创建位图
点击module的右键>>创建xml文件
类型选择为drawable
颜色的位图:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:color="#ffFf0000"/>
<item android:state_selected="false" android:color="#ff00ff00"/>
</selector>
与基本类型的数组不同
Class[] classes ={xx.class,x.class};
发现不使用backgroundTint便不会报错
在xml里面得用app:backgroundTint="@color/red"才有效果,不能用android:backgroundTint.
前面要加上命名空间xmlns:app="http://schemas.android.com/apk/res-auto"
requestWindowFeature(Window.FEATURE_NO_TITLE);
android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP
添加两个依赖
// Required -- JUnit 4 framework
testCompile 'junit:junit:4.12'
// Optional -- Mockito framework
testCompile 'org.mockito:mockito-core:1.10.19'
然后又显示code-1 error
//单元测试显示code -1的error的解决办法
testOptions {
unitTests.returnDefaultValues = true
}
//创建AndroidTestCase的子类
public class TestClass extends AndroidTestCase {
public int add(int x, int y){
return x+y;
}
//测试的方法必须以add作前缀
public void testAdd(){
int x=1;
int y=2;
int result = add(x, y);
//在这里进行断言
assertEquals(4,result);
}
}
Android Studio 中建议过滤的文件:
- .idea 文件夹
- .gradle 文件夹
- 所有的 build 文件夹
- 所有的 .iml 文件
- local.properties 文件
//通过cursor将所有数据传入缩略图数组中
private void getThumbnailColumnData(Cursor cur)
{
if (cur.moveToFirst())
{
int _id;
int image_id;
String image_path;
int _idColumn = cur.getColumnIndex(Thumbnails._ID);
int image_idColumn = cur.getColumnIndex(Thumbnails.IMAGE_ID);
int dataColumn = cur.getColumnIndex(Thumbnails.DATA);
do
{
_id = cur.getInt(_idColumn);
image_id = cur.getInt(image_idColumn);
image_path = cur.getString(dataColumn);
thumbnailList.put("" + image_id, image_path);
} while (cur.moveToNext());
}
}
JSONObject jsonObject = new JSONObject(k);
status = jsonObject.getInt("status");
//次方,第一个参数是底数,第二个参数是次方数
options.inJustDecodeBounds = true 表示只读图片,不加载到内存中,设置这个参数为true,就不会给图片分配内存空间,但是可以获取到图片的大小等属性; 设置为false, 就是要加载这个图片.
设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度
//设置缩小倍数,8的话图片就为原来大小的1/8
private HashMap<String, SoftReference<Bitmap>> imageCache = new HashMap<String, SoftReference<Bitmap>>();
//保存
public void put(String path, Bitmap bmp)
{
if (!TextUtils.isEmpty(path) && bmp != null)
{
imageCache.put(path, new SoftReference<Bitmap>(bmp));
}
}
//使用
public void get(String path){
SoftReference<Bitmap> reference = imageCache.get(path);
Bitmap bmp = reference.get();
if(bmp!=null){
//todo
}
}
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
}
public class FileUtils {
//保存的路径
public static String SDPATH = Environment.getExternalStorageDirectory()
+ "/formats/";
public static void saveBitmap(Bitmap bm, String picName) {
try {
//如果空文件不存在
if (!isFileExist("")) {
File tempf = createSDDir("");
}
File f =getFilePath(SDPATH, picName + ".JPEG");
//如果文件已经存在,则删除
if (f.exists()) {
f.delete();
}
//保存bmp文件到本地文件中
FileOutputStream out = new FileOutputStream(f);
bm.compress(Bitmap.CompressFormat.JPEG,100, out);
out.flush();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//传入文件名,返回路径名
public static File createSDDir(String dirName) throws IOException {
File dir = new File(SDPATH + dirName);
/* //判断sd卡挂载状态,但是都是空的
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
}*/
return dir;
}
//判断文件是否存在
public static boolean isFileExist(String fileName) {
File file = new File(SDPATH + fileName);
file.isFile();
return file.exists();
}
//删除文件
public static void delFile(String fileName) {
File file = new File(SDPATH + fileName);
if (file.isFile()) {
file.delete();
}
file.exists();
}
//删除文件夹
public static void deleteDir() {
File dir = new File(SDPATH);
if (dir == null || !dir.exists() || !dir.isDirectory())
return;
//通过递归删除所有的文件和文件夹
for (File file : dir.listFiles()) {
if (file.isFile())
file.delete();
else if (file.isDirectory())
deleteDir();
}
dir.delete();// 删除目录本身
}
//判断文件是否存在
public static boolean fileIsExists(String path) {
try {
File f = new File(path);
if (!f.exists()) {
return false;
}
} catch (Exception e) {
return false;
}
return true;
}
//通过路径和文件名,返回文件
public static File getFilePath(String filePath, String fileName) {
File file = null;
makeRootDirectory(filePath);
try {
file = new File(filePath + fileName);
} catch (Exception e) {
e.printStackTrace();
}
return file;
}
//判断路径是否存在,如果不存在就创建该路径
public static void makeRootDirectory(String filePath) {
File file = null;
try {
file = new File(filePath);
if (!file.exists()) {
file.mkdir();
}
} catch (Exception e) {
}
}
}
public class IDCardAnddianhua {
Context context;
/*********************************** 身份证验证开始 ****************************************/
/**
* 身份证号码验证 1、号码的结构 公民身份号码是特征组合码,由十七位数字本体码和一位校验码组成。排列顺序从左至右依次为:六位数字地址码,
* 八位数字出生日期码,三位数字顺序码和一位数字校验码。 2、地址码(前六位数)
* 表示编码对象常住户口所在县(市、旗、区)的行政区划代码,按GB/T2260的规定执行。 3、出生日期码(第七位至十四位)
* 表示编码对象出生的年、月、日,按GB/T7408的规定执行,年、月、日代码之间不用分隔符。 4、顺序码(第十五位至十七位)
* 表示在同一地址码所标识的区域范围内,对同年、同月、同日出生的人编定的顺序号, 顺序码的奇数分配给男性,偶数分配给女性。 5、校验码(第十八位数)
* (1)十七位数字本体码加权求和公式 S = Sum(Ai * Wi), i = 0, ... , 16 ,先对前17位数字的权求和
* Ai:表示第i位置上的身份证号码数字值 Wi:表示第i位置上的加权因子 Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
* (2)计算模 Y = mod(S, 11) (3)通过模得到对应的校验码 Y: 0 1 2 3 4 5 6 7 8 9 10 校验码: 1 0 X 9 8 7 6 5 4 3 2
*/
public IDCardAnddianhua(Context context) {
super();
this.context = context;
}
/**
* 功能:判断身份证是否有效
* @param IDStr
* 身份证号
* @return 有效:返回"" 无效:返回String信息
* @throws ParseException
*/
@SuppressWarnings("unchecked")
public boolean IDCardValidate(String IDStr) throws ParseException {
String errorInfo = "";// 记录错误信息
String[] ValCodeArr = { "1", "0", "x", "9", "8", "7", "6", "5", "4",
"3", "2" };
String[] Wi = { "7", "9", "10", "5", "8", "4", "2", "1", "6", "3", "7",
"9", "10", "5", "8", "4", "2" };
String Ai = "";
// ================ 号码的长度 15位或18位 ================
if (IDStr.length() != 15 && IDStr.length() != 18) {
Toast.makeText(context, "身份证号码长度应该为15位或18位", 1).show();
errorInfo = "身份证号码长度应该为15位或18位。";
return false;
}
// =======================(end)========================
// ================ 数字 除最后以为都为数字 ================
if (IDStr.length() == 18) {
Ai = IDStr.substring(0, 17);
} else if (IDStr.length() == 15) {
Ai = IDStr.substring(0, 6) + "19" + IDStr.substring(6, 15);
}
if (isNumeric(Ai) == false) {
Toast.makeText(context, "身份证15位号码都应为数字 ; 18位号码除最后一位外,都应为数字", 1).show();
return false;
}
// =======================(end)========================
// ================ 出生年月是否有效 ================
String strYear = Ai.substring(6, 10);// 年份
String strMonth = Ai.substring(10, 12);// 月份
String strDay = Ai.substring(12, 14);// 月份
if (isDate(strYear + "-" + strMonth + "-" + strDay) == false) {
Toast.makeText(context, "身份证生日无效", 1).show();
return false;
}
GregorianCalendar gc = new GregorianCalendar();
SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd");
try {
if ((gc.get(Calendar.YEAR) - Integer.parseInt(strYear)) > 150
|| (gc.getTime().getTime() - s.parse(
strYear + "-" + strMonth + "-" + strDay).getTime()) < 0) {
Toast.makeText(context, "身份证生日不在有效范围", 1).show();
return false;
}
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (java.text.ParseException e) {
e.printStackTrace();
}
if (Integer.parseInt(strMonth) > 12 || Integer.parseInt(strMonth) == 0) {
Toast.makeText(context, "身份证月份无效", 1).show();
return false;
}
if (Integer.parseInt(strDay) > 31 || Integer.parseInt(strDay) == 0) {
Toast.makeText(context, "身份证月份无效", 1).show();
return false;
}
// =====================(end)=====================
// ================ 地区码时候有效 ================
Hashtable h = GetAreaCode();
if (h.get(Ai.substring(0, 2)) == null) {
// errorInfo = "身份证地区编码错误。";
Toast.makeText(context, "身份证地区编码错误", 1).show();
return false;
}
// ==============================================
// ================ 判断最后一位的值 ================
int TotalmulAiWi = 0;
for (int i = 0; i < 17; i++) {
TotalmulAiWi = TotalmulAiWi
+ Integer.parseInt(String.valueOf(Ai.charAt(i)))
* Integer.parseInt(Wi[i]);
}
int modValue = TotalmulAiWi % 11;
String strVerifyCode = ValCodeArr[modValue];
Ai = Ai + strVerifyCode;
if (IDStr.length() == 18) {
if (Ai.equals(IDStr) == false) {
Toast.makeText(context, "身份证无效,不是合法的身份证号码", 1).show();
return false;
}
} else {
return true;
}
// =====================(end)=====================
return true;
}
/**
* 功能:设置地区编码
* @return Hashtable 对象
*/
@SuppressWarnings("unchecked")
private static Hashtable GetAreaCode() {
Hashtable hashtable = new Hashtable();
hashtable.put("11", "北京");
hashtable.put("12", "天津");
hashtable.put("13", "河北");
hashtable.put("14", "山西");
hashtable.put("15", "内蒙古");
hashtable.put("21", "辽宁");
hashtable.put("22", "吉林");
hashtable.put("23", "黑龙江");
hashtable.put("31", "上海");
hashtable.put("32", "江苏");
hashtable.put("33", "浙江");
hashtable.put("34", "安徽");
hashtable.put("35", "福建");
hashtable.put("36", "江西");
hashtable.put("37", "山东");
hashtable.put("41", "河南");
hashtable.put("42", "湖北");
hashtable.put("43", "湖南");
hashtable.put("44", "广东");
hashtable.put("45", "广西");
hashtable.put("46", "海南");
hashtable.put("50", "重庆");
hashtable.put("51", "四川");
hashtable.put("52", "贵州");
hashtable.put("53", "云南");
hashtable.put("54", "西藏");
hashtable.put("61", "陕西");
hashtable.put("62", "甘肃");
hashtable.put("63", "青海");
hashtable.put("64", "宁夏");
hashtable.put("65", "新疆");
hashtable.put("71", "台湾");
hashtable.put("81", "香港");
hashtable.put("82", "澳门");
hashtable.put("91", "国外");
return hashtable;
}
/**
* 功能:判断字符串是否为数字
*
* @param str
* @return
*/
private static boolean isNumeric(String str) {
Pattern pattern = Pattern.compile("[0-9]*");
Matcher isNum = pattern.matcher(str);
if (isNum.matches()) {
return true;
} else {
return false;
}
}
/**
* 功能:判断字符串是否为日期格式
* @param str
* @return
*/
public static boolean isDate(String strDate) {
Pattern pattern = Pattern
.compile("^((\\d{2}(([02468][048])|([13579][26]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])))))|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))(\\s(((0?[0-9])|([1-2][0-3]))\\:([0-5]?[0-9])((\\s)|(\\:([0-5]?[0-9])))))?$");
Matcher m = pattern.matcher(strDate);
if (m.matches()) {
return true;
} else {
return false;
}
}
}
public class SemaphoreTest {
public static void main(String[] args) {
// 线程池
ExecutorService exec = Executors.newCachedThreadPool();
// 只能5个线程同时访问
final Semaphore semp = new Semaphore(5);
// 模拟20个客户端访问
for (int index = 0; index < 20; index++) {
final int NO = index;
Runnable run = new Runnable() {
public void run() {
try {
// 获取许可
semp.acquire();
Thread.sleep((long) (Math.random() * 10000));
// 访问完后,释放 ,如果屏蔽下面的语句,则在控制台只能打印5条记录,之后线程一直阻塞
semp.release();
} catch (InterruptedException e) {
}
}
};
exec.execute(run);
}
// 退出线程池
exec.shutdown();
}
}
// 获取应用的最大可用内存
int maxMemory = (int) Runtime.getRuntime().maxMemory();
int cacheMemory = maxMemory / 8;
//将LruCache的最大容量设置为应用最大容量的1/8,
//它像是一个链表一样,当容量超过最大容量的时候,将最先添加的容量删除直至小于最大容量
//底层也是用hashmap实现的,没有软引用
LruCache<String, Bitmap> mLruCache = new LruCache<String, Bitmap>(cacheMemory) {
@Override
//返回每个item的大小
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
};
// 后台轮询线程
mPoolThread = new Thread() {
@Override
public void run() {
Looper.prepare();
//todo
Looper.loop();
}
};
mPoolThread.start();
public static boolean downloadImgByUrl(String urlStr, File file) {
FileOutputStream fos = null;
InputStream is = null;
try {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
is = conn.getInputStream();
fos = new FileOutputStream(file);
byte[] buf = new byte[512];
int len = 0;
while ((len = is.read(buf)) != -1) {
fos.write(buf, 0, len);
}
fos.flush();
return true;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (is != null)
is.close();
} catch (IOException e) {
}
try {
if (fos != null)
fos.close();
} catch (IOException e) {
}
}
return false;
}
public static ImageSize getImageViewSize(ImageView imageView) {
ImageSize imageSize = new ImageSize();
DisplayMetrics displayMetrics = imageView.getContext().getResources()
.getDisplayMetrics();
LayoutParams lp = imageView.getLayoutParams();
int width = imageView.getWidth();// 获取imageview的实际宽度
if (width <= 0) {
// 获取imageview在layout中声明的宽度
width = lp.width;
}
if (width <= 0) {
// 检查最大值
//width = imageView.getMaxWidth();
width = getImageViewFieldValue(imageView, "mMaxWidth");
}
if (width <= 0) {
//获取iv的矩阵的宽度
width = displayMetrics.widthPixels;
}
int height = imageView.getHeight();// 获取imageview的实际高度
if (height <= 0) {
// 获取imageview在layout中声明的宽度
height = lp.height;
}
if (height <= 0) {
// 检查最大值
height = getImageViewFieldValue(imageView, "mMaxHeight");
}
if (height <= 0) {
//获取iv的矩阵宽度
height = displayMetrics.heightPixels;
}
imageSize.width = width;
imageSize.height = height;
return imageSize;
}
通过空间的宽高进行图片的压缩
bitmap = BitmapFactory.decodeStream(is, null, opts);
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int newWidth = imageViewSize.width;
int newHeight = imageViewSize.height;
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
float bls = scaleWidth > scaleHeight ? scaleWidth : scaleHeight;
Matrix matrix = new Matrix();
matrix.postScale(bls, bls);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false);
public static int caculateInSampleSize(Options options, int reqWidth,
int reqHeight) {
int width = options.outWidth;
int height = options.outHeight;
int inSampleSize = 1;
if (width > reqWidth || height > reqHeight) {
int widthRadio = Math.round(width * 1.0f / reqWidth);
int heightRadio = Math.round(height * 1.0f / reqHeight);
inSampleSize = Math.max(widthRadio, heightRadio);
}
return inSampleSize;
}
进行缩放压缩
protected Bitmap decodeSampledBitmapFromPath(String path, int width,
int height) {
// 获得图片的宽和高,并不把图片加载到内存中
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
options.inSampleSize = caculateInSampleSize(options,
width, height);
// 使用获得到的InSampleSize再次解析图片
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeFile(path, options);
return bitmap;
}
private static int getImageViewFieldValue(Object object, String fieldName) {
int value = 0;
try {
Field field = ImageView.class.getDeclaredField(fieldName);
field.setAccessible(true);
int fieldValue = field.getInt(object);
if (fieldValue > 0 && fieldValue < Integer.MAX_VALUE) {
value = fieldValue;
}
} catch (Exception e) {
}
return value;
}
public File getDiskCacheDir(Context context, String uniqueName) {
String cachePath;
if (Environment.MEDIA_MOUNTED.equals(Environment
.getExternalStorageState())) {
cachePath = context.getExternalCacheDir().getPath();
} else {
cachePath = context.getCacheDir().getPath();
}
return new File(cachePath + File.separator + uniqueName);
}
public String bytes2hex02(byte[] bytes) {
StringBuilder sb = new StringBuilder();
String tmp = null;
for (byte b : bytes) {
// 将每个字节与0xFF进行与运算,然后转化为10进制,然后借助于Integer再转化为16进制
tmp = Integer.toHexString(0xFF & b);
if (tmp.length() == 1)// 每个字节8为,转为16进制标志,2个16进制位
{
tmp = "0" + tmp;
}
sb.append(tmp);
}
return sb.toString();
}
public class loaderBitmap {
//内存缓存
static LruCache<String, Bitmap> lruCache = null;
static {
//LruCache的大小设置为4m
int maxsize = 4 * 1024 * 1024;
lruCache = new LruCache<String, Bitmap>(maxsize) {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
};
}
/**
* @param context
* @param url
* @return
*/
public static Bitmap setBitmapFromCache(Context context, String url) {
if (TextUtils.isEmpty(url)) {
return null;
}
Bitmap bitmap = null;
//先从内存缓存中查找图片资源
bitmap = getBitmapFromMemotyCache(url);
if (bitmap != null) {
return bitmap;
}
//再从应用的缓存目录中查找图片
bitmap = getBitmapFormFileCache(context, url);
if (bitmap != null) {
return bitmap;
}
//再从网络上去异步请求
bitmap = getBitmapAsyncLoad(url, context);
if (bitmap != null) {
return bitmap;
}
return null;
}
//从缓存文件中取数据
private static Bitmap getBitmapFormFileCache(Context context, String url) {
Bitmap bitmap = null;
String fileName = url.substring(url.lastIndexOf("/") + 1);
//获得应用的缓存目录
File cacheDir = null;
try {
cacheDir = context.getCacheDir();
} catch (Exception e) {
e.printStackTrace();
}
if (cacheDir != null) {
File[] files = cacheDir.listFiles();
for (int i = 0; i < files.length; i++) {
if (files[i].getName().equals(fileName)) {
bitmap = BitmapFactory.decodeFile(files[i].getAbsolutePath());
return bitmap;
}
}
}
return null;
}
//从lrucache中取bmp
private static Bitmap getBitmapFromMemotyCache(String url) {
Bitmap bitmap = null;
if (url != null) {
bitmap = lruCache.get(url);
}
return bitmap;
}
//从网络中请求数据
private static Bitmap getBitmapAsyncLoad(String url,
Context context) {
MyAsyncTask task = new MyAsyncTask(context);
task.execute(url);
return null;
}
//异步任务
static class MyAsyncTask extends AsyncTask<String, Void, Bitmap> {
Context context;
public MyAsyncTask(Context context) {
this.context = context;
}
@Override
protected Bitmap doInBackground(String... params) {
Bitmap bitmap = null;
String path = params[0];
try {
URL url = new URL(path);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(5000);
connection.setRequestMethod("GET");
connection.setDoInput(true);
if (connection.getResponseCode() == 200) {
InputStream inputStream = connection.getInputStream();
//把返回的图片资源做按比例缩放的处理
bitmap = CompressBitmap(inputStream);
//存入缓存
if (bitmap != null) {
lruCache.put(path, bitmap);
bitmapCacheFile(bitmap, path, context);
}
}
} catch (Exception e) {
// TODO: handle exception
}
return null;
}
@Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
}
//保存到本地缓存
private void bitmapCacheFile(Bitmap bitmap, String path,
Context context2) throws FileNotFoundException {
File cacheFile = context2.getCacheDir();
// TODO Auto-generated method stub
if (!cacheFile.exists()) {
cacheFile.mkdirs();
}
String fileName = path.substring(path.lastIndexOf("/") + 1);
File file = new File(cacheFile, fileName);
OutputStream stream = new FileOutputStream(file);
bitmap.compress(CompressFormat.JPEG, 100, stream);
}
//对图片进行压缩
private Bitmap CompressBitmap(InputStream inputStream) {
byte[] datas = StreamUtil.getBytesFromStream(inputStream);
BitmapFactory.Options options = new BitmapFactory.Options();
//只获取图片的参数
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(datas, 0, datas.length, options);
//边界的宽高
int outWidth = options.outWidth;
int outHeight = options.outHeight;
int targetWidth = 70;
int targetHeight = 70;
int wbl = outWidth / targetWidth;
int hbl = outHeight / targetHeight;
int bl = wbl > hbl ? wbl : hbl;
if (bl < 0) {
bl = 1;
}
options.inSampleSize = bl;
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeByteArray(datas, 0, datas.length, options);
return bitmap;
}
}
}
public class MD5 {
/**
* MD5的算法在RFC1321 中定 在RFC 1321中,给出了Test suite用来验你的实现是否正确: MD5 ("") =
* d41d8cd98f00b204e9800998ecf8427e MD5 ("a") =
* 0cc175b9c0f1b6a831c399e269772661 MD5 ("abc") =
* 900150983cd24fb0d6963f7d28e17f72 MD5 ("message digest") =
* f96b697d7cb7938d525a2f31aaf161d0 MD5 ("abcdefghijklmnopqrstuvwxyz") =
* c3fcd3d76192e4007dfb496cca67e13b
*/
//传入一个字节数组,返回一个md5的字符串
public static String getMD5(byte[] source) {
String s = null;
//16进制的数
char hexDigits[] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
try {
java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
md.update(source);
byte tmp[] = md.digest();
//MD5的计算结果是128证数,也就是16个字节
//每个字节等于2个16进制数字
char str[] = new char[16 * 2];
// 表示转换结果中对应的字符位置
int k = 0;
for (int i = 0; i < 16; i++) {
byte byte0 = tmp[i]; // 取第 i 个字
// >>>为逻辑右移,将符号位置一起移动
// 取字节中高4 位的数字转换,
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
// 取字节中低4 位的数字转换
str[k++] = hexDigits[byte0 & 0xf];
}
// 换后的结果转换为字符串
s = new String(str);
} catch (Exception e) {
e.printStackTrace();
}
return s;
}
/*
* 下面这些S11-S44实际上是 4*4的矩阵,在原始的C实现中是 #define 实现的, 这里把他们实现成为static
* final是表示了只读,切能在同一个进程空间内的多 Instance间共
*/
static final int S11 = 7;
static final int S12 = 12;
static final int S13 = 17;
static final int S14 = 22;
static final int S21 = 5;
static final int S22 = 9;
static final int S23 = 14;
static final int S24 = 20;
static final int S31 = 4;
static final int S32 = 11;
static final int S33 = 16;
static final int S34 = 23;
static final int S41 = 6;
static final int S42 = 10;
static final int S43 = 15;
static final int S44 = 21;
static final byte[] PADDING = { -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0 };
/*
* 下面的三个成员是MD5计算过程中用到的3个核心数据,在原始的C实现 被定义到MD5_CTX结构
*/
private long[] state = new long[4]; // state (ABCD)
private long[] count = new long[2]; // number of bits, modulo 2^64 (lsb
// first)
private byte[] buffer = new byte[64]; // input buffer
/*
* digestHexStr是MD5的唯一一个公共成员,是最新一次计算结果的 16进制ASCII表示.
*/
public String digestHexStr;
/*
* digest,是最新一次计算结果的2进制内部表示,表 128bit的MD5 .
*/
private byte[] digest = new byte[16];
/*
* getMD5ofStr是类MD5 主要的公共方法,入口参数是你想要进行MD5变换的字符串
* 返回的是变换完的结果,这个结果是从公共成员digestHexStr取得的.
*/
public String getMD5ofStr(String inbuf) {
md5Init();
md5Update(inbuf.getBytes(), inbuf.length());
md5Final();
digestHexStr = "";
for (int i = 0; i < 16; i++) {
digestHexStr += byteHEX(digest[i]);
}
return digestHexStr;
}
// 这是MD5这个类的标准结构函数,JavaBean 求有 个public的并且没有参数的构 ?函
public MD5() {
md5Init();
return;
}
/* md5Init是个初始化函数,初始化核心变量,装入标准的幻 */
private void md5Init() {
count[0] = 0L;
count[1] = 0L;
// 魔法数字:初始化常量
state[0] = 0x67452301L;
state[1] = 0xefcdab89L;
state[2] = 0x98badcfeL;
state[3] = 0x10325476L;
return;
}
/*
* F, G, H ,I 4个基本的MD5函数,在原始的MD5的C实现中,由于他们
* 单的位运算,可能出于效率的考虑把他们实现成了宏,在java中,我们把他 实现成了private方法,名字保持了原来C中的
*/
private long F(long x, long y, long z) {
return (x & y) | ((~x) & z);
}
private long G(long x, long y, long z) {
return (x & z) | (y & (~z));
}
private long H(long x, long y, long z) {
return x ^ y ^ z;
}
private long I(long x, long y, long z) {
return y ^ (x | (~z));
}
/*
* FF,GG,HH和II将调用F,G,H,I进行近一步变 FF, GG, HH, and II transformations for
* rounds 1, 2, 3, and 4. Rotation is separate from addition to prevent
* recomputation.
*/
private long FF(long a, long b, long c, long d, long x, long s, long ac) {
a += F(b, c, d) + x + ac;
a = ((int) a << s) | ((int) a >>> (32 - s));
a += b;
return a;
}
private long GG(long a, long b, long c, long d, long x, long s, long ac) {
a += G(b, c, d) + x + ac;
a = ((int) a << s) | ((int) a >>> (32 - s));
a += b;
return a;
}
private long HH(long a, long b, long c, long d, long x, long s, long ac) {
a += H(b, c, d) + x + ac;
a = ((int) a << s) | ((int) a >>> (32 - s));
a += b;
return a;
}
private long II(long a, long b, long c, long d, long x, long s, long ac) {
a += I(b, c, d) + x + ac;
a = ((int) a << s) | ((int) a >>> (32 - s));
a += b;
return a;
}
/*
* md5Update是MD5的主计算过程,inbuf是要变换的字节串,inputlen是长度,这个
* 函数由getMD5ofStr调用,调用之前需要调用md5init,因此把他设计成private
*/
private void md5Update(byte[] inbuf, int inputLen) {
int i, index, partLen;
byte[] block = new byte[64];
index = (int) (count[0] >>> 3) & 0x3F;
if ((count[0] += (inputLen << 3)) < (inputLen << 3))
count[1]++;
count[1] += (inputLen >>> 29);
partLen = 64 - index;
// Transform as many times as possible.
if (inputLen >= partLen) {
md5Memcpy(buffer, inbuf, index, 0, partLen);
md5Transform(buffer);
for (i = partLen; i + 63 < inputLen; i += 64) {
md5Memcpy(block, inbuf, 0, i, 64);
md5Transform(block);
}
index = 0;
} else
i = 0;
md5Memcpy(buffer, inbuf, index, i, inputLen - i);
}
/*
* md5Final整理和填写输出结
*/
private void md5Final() {
byte[] bits = new byte[8];
int index, padLen;
// /* Save number of bits */
Encode(bits, count, 8);
// /* Pad out to 56 mod 64.
index = (int) (count[0] >>> 3) & 0x3f;
padLen = (index < 56) ? (56 - index) : (120 - index);
md5Update(PADDING, padLen);
// /* Append length (before padding) */
md5Update(bits, 8);
// /* Store state in digest */
Encode(digest, state, 16);
}
/*
* md5Memcpy是个内部使用的byte数组的块拷贝函数,从input的inpos 始把len长度 字节拷贝到output的outpos位置
*/
private void md5Memcpy(byte[] output, byte[] input, int outpos, int inpos, int len) {
int i;
for (i = 0; i < len; i++)
output[outpos + i] = input[inpos + i];
}
/*
* md5Transform是MD5核心变换程式,有md5Update调用,block是分块的原始字节
*/
private void md5Transform(byte block[]) {
long a = state[0], b = state[1], c = state[2], d = state[3];
long[] x = new long[16];
Decode(x, block, 64);
/* Round 1 */
a = FF(a, b, c, d, x[0], S11, 0xd76aa478L); /* 1 */
d = FF(d, a, b, c, x[1], S12, 0xe8c7b756L); /* 2 */
c = FF(c, d, a, b, x[2], S13, 0x242070dbL); /* 3 */
b = FF(b, c, d, a, x[3], S14, 0xc1bdceeeL); /* 4 */
a = FF(a, b, c, d, x[4], S11, 0xf57c0fafL); /* 5 */
d = FF(d, a, b, c, x[5], S12, 0x4787c62aL); /* 6 */
c = FF(c, d, a, b, x[6], S13, 0xa8304613L); /* 7 */
b = FF(b, c, d, a, x[7], S14, 0xfd469501L); /* 8 */
a = FF(a, b, c, d, x[8], S11, 0x698098d8L); /* 9 */
d = FF(d, a, b, c, x[9], S12, 0x8b44f7afL); /* 10 */
c = FF(c, d, a, b, x[10], S13, 0xffff5bb1L); /* 11 */
b = FF(b, c, d, a, x[11], S14, 0x895cd7beL); /* 12 */
a = FF(a, b, c, d, x[12], S11, 0x6b901122L); /* 13 */
d = FF(d, a, b, c, x[13], S12, 0xfd987193L); /* 14 */
c = FF(c, d, a, b, x[14], S13, 0xa679438eL); /* 15 */
b = FF(b, c, d, a, x[15], S14, 0x49b40821L); /* 16 */
/* Round 2 */
a = GG(a, b, c, d, x[1], S21, 0xf61e2562L); /* 17 */
d = GG(d, a, b, c, x[6], S22, 0xc040b340L); /* 18 */
c = GG(c, d, a, b, x[11], S23, 0x265e5a51L); /* 19 */
b = GG(b, c, d, a, x[0], S24, 0xe9b6c7aaL); /* 20 */
a = GG(a, b, c, d, x[5], S21, 0xd62f105dL); /* 21 */
d = GG(d, a, b, c, x[10], S22, 0x2441453L); /* 22 */
c = GG(c, d, a, b, x[15], S23, 0xd8a1e681L); /* 23 */
b = GG(b, c, d, a, x[4], S24, 0xe7d3fbc8L); /* 24 */
a = GG(a, b, c, d, x[9], S21, 0x21e1cde6L); /* 25 */
d = GG(d, a, b, c, x[14], S22, 0xc33707d6L); /* 26 */
c = GG(c, d, a, b, x[3], S23, 0xf4d50d87L); /* 27 */
b = GG(b, c, d, a, x[8], S24, 0x455a14edL); /* 28 */
a = GG(a, b, c, d, x[13], S21, 0xa9e3e905L); /* 29 */
d = GG(d, a, b, c, x[2], S22, 0xfcefa3f8L); /* 30 */
c = GG(c, d, a, b, x[7], S23, 0x676f02d9L); /* 31 */
b = GG(b, c, d, a, x[12], S24, 0x8d2a4c8aL); /* 32 */
/* Round 3 */
a = HH(a, b, c, d, x[5], S31, 0xfffa3942L); /* 33 */
d = HH(d, a, b, c, x[8], S32, 0x8771f681L); /* 34 */
c = HH(c, d, a, b, x[11], S33, 0x6d9d6122L); /* 35 */
b = HH(b, c, d, a, x[14], S34, 0xfde5380cL); /* 36 */
a = HH(a, b, c, d, x[1], S31, 0xa4beea44L); /* 37 */
d = HH(d, a, b, c, x[4], S32, 0x4bdecfa9L); /* 38 */
c = HH(c, d, a, b, x[7], S33, 0xf6bb4b60L); /* 39 */
b = HH(b, c, d, a, x[10], S34, 0xbebfbc70L); /* 40 */
a = HH(a, b, c, d, x[13], S31, 0x289b7ec6L); /* 41 */
d = HH(d, a, b, c, x[0], S32, 0xeaa127faL); /* 42 */
c = HH(c, d, a, b, x[3], S33, 0xd4ef3085L); /* 43 */
b = HH(b, c, d, a, x[6], S34, 0x4881d05L); /* 44 */
a = HH(a, b, c, d, x[9], S31, 0xd9d4d039L); /* 45 */
d = HH(d, a, b, c, x[12], S32, 0xe6db99e5L); /* 46 */
c = HH(c, d, a, b, x[15], S33, 0x1fa27cf8L); /* 47 */
b = HH(b, c, d, a, x[2], S34, 0xc4ac5665L); /* 48 */
/* Round 4 */
a = II(a, b, c, d, x[0], S41, 0xf4292244L); /* 49 */
d = II(d, a, b, c, x[7], S42, 0x432aff97L); /* 50 */
c = II(c, d, a, b, x[14], S43, 0xab9423a7L); /* 51 */
b = II(b, c, d, a, x[5], S44, 0xfc93a039L); /* 52 */
a = II(a, b, c, d, x[12], S41, 0x655b59c3L); /* 53 */
d = II(d, a, b, c, x[3], S42, 0x8f0ccc92L); /* 54 */
c = II(c, d, a, b, x[10], S43, 0xffeff47dL); /* 55 */
b = II(b, c, d, a, x[1], S44, 0x85845dd1L); /* 56 */
a = II(a, b, c, d, x[8], S41, 0x6fa87e4fL); /* 57 */
d = II(d, a, b, c, x[15], S42, 0xfe2ce6e0L); /* 58 */
c = II(c, d, a, b, x[6], S43, 0xa3014314L); /* 59 */
b = II(b, c, d, a, x[13], S44, 0x4e0811a1L); /* 60 */
a = II(a, b, c, d, x[4], S41, 0xf7537e82L); /* 61 */
d = II(d, a, b, c, x[11], S42, 0xbd3af235L); /* 62 */
c = II(c, d, a, b, x[2], S43, 0x2ad7d2bbL); /* 63 */
b = II(b, c, d, a, x[9], S44, 0xeb86d391L); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
}
/*
* Encode把long数组按顺序拆成byte数组,因为java的long类型 64bit的, 只拆 32bit,以适应原始C实现的用
*/
private void Encode(byte[] output, long[] input, int len) {
int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (byte) (input[i] & 0xffL);
output[j + 1] = (byte) ((input[i] >>> 8) & 0xffL);
output[j + 2] = (byte) ((input[i] >>> 16) & 0xffL);
output[j + 3] = (byte) ((input[i] >>> 24) & 0xffL);
}
}
/*
* Decode把byte数组按顺序合成成long数组,因为java的long类型 64bit的,
* 只合成低32bit,高32bit清零,以适应原始C实现的用
*/
private void Decode(long[] output, byte[] input, int len) {
int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = b2iu(input[j]) | (b2iu(input[j + 1]) << 8) | (b2iu(input[j + 2]) << 16)
| (b2iu(input[j + 3]) << 24);
return;
}
/*
* 把byte按照不虑虑正负号的原则的"升位"程式,因为java没有unsigned运算
*/
public static long b2iu(byte b) {
return b < 0 ? b & 0x7F + 128 : b;
}
//用来把一个byte类型的数转换成十六进制的ASCII表示
public static String byteHEX(byte ib) {
char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
char[] ob = new char[2];
ob[0] = Digit[(ib >>> 4) & 0X0F];
ob[1] = Digit[ib & 0X0F];
String s = new String(ob);
return s;
}
public static void main(String argv[]) {
System.out.println(MD5.getMD5("123".getBytes()));
}
}
public class StreamUtil {
//把inputStrem转换为String
public static byte[] getBytesFromStream(InputStream is){
byte[] datas=null;
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = is.read(buffer)) != -1) {
outputStream.write(buffer,0,len);
}
datas=outputStream.toByteArray();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}finally{
if(is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return datas;
}
}
public class ZoomImageView extends ImageView implements OnScaleGestureListener,
OnTouchListener, ViewTreeObserver.OnGlobalLayoutListener
{
private static final String TAG = ZoomImageView.class.getSimpleName();
public static final float SCALE_MAX = 4.0f;
private static final float SCALE_MID = 2.0f;
/**
* 初始化时的缩放比例,如果图片宽或高大于屏幕,此值将小于0
*/
private float initScale = 1.0f;
private boolean once = true;
/**
* 用于存放矩阵的9个值
*/
private final float[] matrixValues = new float[9];
/**
* 缩放的手势检测
*/
private ScaleGestureDetector mScaleGestureDetector = null;
private final Matrix mScaleMatrix = new Matrix();
/**
* 用于双击检测
*/
private GestureDetector mGestureDetector;
private boolean isAutoScale;
private int mTouchSlop;
private float mLastX;
private float mLastY;
private boolean isCanDrag;
private int lastPointerCount;
private boolean isCheckTopAndBottom = true;
private boolean isCheckLeftAndRight = true;
public ZoomImageView(Context context)
{
this(context, null);
}
public ZoomImageView(Context context, AttributeSet attrs)
{
super(context, attrs);
super.setScaleType(ScaleType.MATRIX);
//手势事件的监听:双击
mGestureDetector = new GestureDetector(context,
new SimpleOnGestureListener()
{
@Override
public boolean onDoubleTap(MotionEvent e)
{
//如果是自动缩放,则终止该方法
if (isAutoScale == true)
return true;
float x = e.getX();
float y = e.getY();
//获取缩放比例,对此进行判断,并设置到自动缩放的任务
if (getScale() < SCALE_MID)
{
ZoomImageView.this.postDelayed(
new AutoScaleRunnable(SCALE_MID, x, y), 16);
isAutoScale = true;
} else if (getScale() >= SCALE_MID
&& getScale() < SCALE_MAX)
{
ZoomImageView.this.postDelayed(
new AutoScaleRunnable(SCALE_MAX, x, y), 16);
isAutoScale = true;
} else
{
ZoomImageView.this.postDelayed(
new AutoScaleRunnable(initScale, x, y), 16);
isAutoScale = true;
}
return true;
}
});
//缩放手势的监听
mScaleGestureDetector = new ScaleGestureDetector(context, this);
this.setOnTouchListener(this);
}
/**
* 自动缩放的任务
*
* @author zhy
*
*/
private class AutoScaleRunnable implements Runnable
{
static final float BIGGER = 1.07f;
static final float SMALLER = 0.93f;
private float mTargetScale;
private float tmpScale;
/**
* 缩放的中心
*/
private float x;
private float y;
/**
* 传入目标缩放值,
* 根据目标值与当前值,判断应该放大还是缩小
* @param targetScale
*/
public AutoScaleRunnable(float targetScale, float x, float y)
{
this.mTargetScale = targetScale;
this.x = x;
this.y = y;
if (getScale() < mTargetScale)
{
tmpScale = BIGGER;
} else
{
tmpScale = SMALLER;
}
}
@Override
public void run()
{
// 进行缩放
mScaleMatrix.postScale(tmpScale, tmpScale, x, y);
checkBorderAndCenterWhenScale();
setImageMatrix(mScaleMatrix);
final float currentScale = getScale();
// 如果值在合法范围内,继续缩放
if (((tmpScale > 1f) && (currentScale < mTargetScale))
|| ((tmpScale < 1f) && (mTargetScale < currentScale)))
{
ZoomImageView.this.postDelayed(this, 16);
} else
// 设置为目标的缩放比例
{
final float deltaScale = mTargetScale / currentScale;
mScaleMatrix.postScale(deltaScale, deltaScale, x, y);
checkBorderAndCenterWhenScale();
setImageMatrix(mScaleMatrix);
isAutoScale = false;
}
}
}
//缩放手势的操作
@SuppressLint("NewApi")
@Override
public boolean onScale(ScaleGestureDetector detector)
{
float scale = getScale();
float scaleFactor = detector.getScaleFactor();
if (getDrawable() == null)
return true;
/**
* 缩放的范围控制
*/
if ((scale < SCALE_MAX && scaleFactor > 1.0f)
|| (scale > initScale && scaleFactor < 1.0f))
{
/**
* 最大值最小值判断
*/
if (scaleFactor * scale < initScale)
{
scaleFactor = initScale / scale;
}
if (scaleFactor * scale > SCALE_MAX)
{
scaleFactor = SCALE_MAX / scale;
}
/**
* 设置缩放比例
*/
mScaleMatrix.postScale(scaleFactor, scaleFactor,
detector.getFocusX(), detector.getFocusY());
checkBorderAndCenterWhenScale();
setImageMatrix(mScaleMatrix);
}
return true;
}
/**
* 在缩放时,进行图片显示范围的控制
*/
private void checkBorderAndCenterWhenScale()
{
RectF rect = getMatrixRectF();
float deltaX = 0;
float deltaY = 0;
int width = getWidth();
int height = getHeight();
// 如果宽或高大于屏幕,则控制范围
if (rect.width() >= width)
{
if (rect.left > 0)
{
deltaX = -rect.left;
}
if (rect.right < width)
{
deltaX = width - rect.right;
}
}
if (rect.height() >= height)
{
if (rect.top > 0)
{
deltaY = -rect.top;
}
if (rect.bottom < height)
{
deltaY = height - rect.bottom;
}
}
// 如果宽或高小于屏幕,则让其居中
if (rect.width() < width)
{
deltaX = width * 0.5f - rect.right + 0.5f * rect.width();
}
if (rect.height() < height)
{
deltaY = height * 0.5f - rect.bottom + 0.5f * rect.height();
}
mScaleMatrix.postTranslate(deltaX, deltaY);
}
/**
* 根据当前图片的Matrix获得图片的范围
*
* @return
*/
private RectF getMatrixRectF()
{
Matrix matrix = mScaleMatrix;
RectF rect = new RectF();
Drawable d = getDrawable();
if (null != d)
{
rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
matrix.mapRect(rect);
}
return rect;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector)
{
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector)
{
}
//触摸事件的监听
@Override
public boolean onTouch(View v, MotionEvent event)
{
if (mGestureDetector.onTouchEvent(event))
return true;
mScaleGestureDetector.onTouchEvent(event);
float x = 0, y = 0;
// 拿到触摸点的个数
final int pointerCount = event.getPointerCount();
// 得到多个触摸点的x与y均值
for (int i = 0; i < pointerCount; i++)
{
x += event.getX(i);
y += event.getY(i);
}
x = x / pointerCount;
y = y / pointerCount;
/**
* 每当触摸点发生变化时,重置mLasX , mLastY
*/
if (pointerCount != lastPointerCount)
{
isCanDrag = false;
mLastX = x;
mLastY = y;
}
//保存最后一次的触摸点个数
lastPointerCount = pointerCount;
RectF rectF = getMatrixRectF();
//解决触摸时间的冲突
switch (event.getAction())
{
//对比图片的matrix和屏幕的宽高 >>确定事件是否拦截
case MotionEvent.ACTION_DOWN:
//当图片的宽度大于屏幕的空间的宽度的时候
if (rectF.width() > getWidth() || rectF.height() > getHeight())
{
getParent().requestDisallowInterceptTouchEvent(true);
}
break;
case MotionEvent.ACTION_MOVE:
if (rectF.width() > getWidth() || rectF.height() > getHeight())
{
getParent().requestDisallowInterceptTouchEvent(true);
}
float dx = x - mLastX;
float dy = y - mLastY;
if (!isCanDrag)
{
isCanDrag = isCanDrag(dx, dy);
}
if (isCanDrag)
{
if (getDrawable() != null)
{
isCheckLeftAndRight = isCheckTopAndBottom = true;
// 如果宽度小于屏幕宽度,则禁止左右移动
if (rectF.width() < getWidth())
{
dx = 0;
isCheckLeftAndRight = false;
}
// 如果高度小雨屏幕高度,则禁止上下移动
if (rectF.height() < getHeight())
{
dy = 0;
isCheckTopAndBottom = false;
}
mScaleMatrix.postTranslate(dx, dy);
checkMatrixBounds();
setImageMatrix(mScaleMatrix);
}
}
mLastX = x;
mLastY = y;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
lastPointerCount = 0;
break;
}
return true;
}
/**
* 获得当前的缩放比例
*
* @return
*/
public final float getScale()
{
mScaleMatrix.getValues(matrixValues);
return matrixValues[Matrix.MSCALE_X];
}
@Override
protected void onAttachedToWindow()
{
super.onAttachedToWindow();
getViewTreeObserver().addOnGlobalLayoutListener(this);
}
@SuppressWarnings("deprecation")
@Override
protected void onDetachedFromWindow()
{
super.onDetachedFromWindow();
getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
@Override
public void onGlobalLayout()
{
if (once)
{
Drawable d = getDrawable();
if (d == null)
return;
Log.e(TAG, d.getIntrinsicWidth() + " , " + d.getIntrinsicHeight());
int width = getWidth();
int height = getHeight();
// 拿到图片的宽和高
int dw = d.getIntrinsicWidth();
int dh = d.getIntrinsicHeight();
float scale = 1.0f;
// 如果图片的宽或者高大于屏幕,则缩放至屏幕的宽或者高
if (dw > width && dh <= height)
{
scale = width * 1.0f / dw;
}
if (dh > height && dw <= width)
{
scale = height * 1.0f / dh;
}
// 如果宽和高都大于屏幕,则让其按按比例适应屏幕大小
if (dw > width && dh > height)
{
scale = Math.min(width * 1.0f / dw, height * 1.0f / dh);
}
initScale = scale;
Log.e(TAG, "initScale = " + initScale);
mScaleMatrix.postTranslate((width - dw) / 2, (height - dh) / 2);
mScaleMatrix.postScale(scale, scale, getWidth() / 2,
getHeight() / 2);
// 图片移动至屏幕中心
setImageMatrix(mScaleMatrix);
once = false;
}
}
/**
* 移动时,进行边界判断,主要判断宽或高大于屏幕的
*/
private void checkMatrixBounds()
{
RectF rect = getMatrixRectF();
float deltaX = 0, deltaY = 0;
final float viewWidth = getWidth();
final float viewHeight = getHeight();
// 判断移动或缩放后,图片显示是否超出屏幕边界
if (rect.top > 0 && isCheckTopAndBottom)
{
deltaY = -rect.top;
}
if (rect.bottom < viewHeight && isCheckTopAndBottom)
{
deltaY = viewHeight - rect.bottom;
}
if (rect.left > 0 && isCheckLeftAndRight)
{
deltaX = -rect.left;
}
if (rect.right < viewWidth && isCheckLeftAndRight)
{
deltaX = viewWidth - rect.right;
}
mScaleMatrix.postTranslate(deltaX, deltaY);
}
/**
* 是否是推动行为
*
* @param dx
* @param dy
* @return
*/
private boolean isCanDrag(float dx, float dy)
{
return Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop;
}
}
getParent().requestDisallowInterceptTouchEvent(true);
在setting中打开project struct
点击要删除的module
点击左上方的-号
ok
以project打开项目
右键需要删除的module
在android开发板中使用M13模块的nfc读卡器的时候,添加so文件失败,怎么想也不明白,
后来在网上找了一篇有用的蚊帐;
Module的根目录中建立libs目录,将so文件复制进去
在module的gradle
android {
.......
task nativeLibsToJar(type: Zip, description: "create a jar archive of the native libs") {
destinationDir file("$projectDir/libs")
baseName "Native_Libs2"
extension "jar"
from fileTree(dir: "libs", include: "**/*.so")
into "lib"
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn(nativeLibsToJar)
}
}
平时用的添加so库方法:
1.创建src/main/jniLibs文件夹
复制so文件到该文件中
2.在module的gradle中
android {
.......
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
3.build/makeproject
切换android视图,就可以看先so文件已经变成了jar文件了
在需要检查的代码开头和结尾打上断点
右键 run as debug
反复写了一万遍,转换结果都是乱码
网上查到原来可能是android studio中UTF-8失效的问题
//好用的工具类
public static String hex2String(String s){
byte[] baKeyword = new byte[s.length()/2];
for(int i = 0; i < baKeyword.length; i++){
try{
baKeyword[i] = (byte)(0xff & Integer.parseInt(s.substring(i*2, i*2+2),16));
}catch(Exception e){
e.printStackTrace();
}
}
try{
s = new String(baKeyword, "GB2312");
}catch (Exception e1){
e1.printStackTrace();
}
return s;
}
Collection.sort(list,comparator);
Comparator<Double> comparator=new Comparator<>{
public int compare(Double dl,double d2){
return p1>=p2 ?1:-1;
}
}
<style name="xx">
<item name="textsize">12sp<>
<item name=textColor>...
</style>
2.在布局中引用样式
<Tv
Style="@style/xx">
注意和android:textStyle的区别,用错了会崩溃
配置文件中:
<application android:largelHeap="true"
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP)
//发送延时的message给handler mHandler.sendEmptyMessageDelayed(MESSAGE_SCROLL_TO,DELAYED_TIME);
gravity失效,因为gravity作用域内容,layoutgravity才是作用于控件在父控件中的位置的
<activity android:name=".MainActivity" android:screenOrientation="portrait">
decorView = getWindow().getDecorView();
int uiOptions =
//隐藏导航栏
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
//设置全屏:隐藏状态栏
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
//设置layout是否全屏(与状态栏位置重叠)
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
//真正意义上的全屏
| View.SYSTEM_UI_FLAG_IMMERSIVE;
decorView.setSystemUiVisibility(uiOptions);
decorView.setVisibility(View.GONE);
Caused by: java.lang.SecurityException: StatusBarManagerService: Neither user 10056 nor current process has android.permission.STATUS_BAR.
因为需要两个权限,而其中statubar的权限需要系统签名,获取系统签名的方法自行百度
<uses-permission android:name="android.permission.STATUS_BAR" />
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
public static final int DISABLE_EXPAND = 0x00010000;//4.2以上的整形标识
public static final int DISABLE_EXPAND_LOW = 0x00000001;//4.2以下的整形标识
public static final int DISABLE_NONE = 0x00000000;//取消StatusBar所有disable属性
//在onWindowFocusChanged()中屏蔽下拉效果
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
banStatusBar();
}
//取消下拉的屏蔽
private void unBanStatusBar() {
Object service = getSystemService("statusbar");
try {
Class<?> statusBarManager = Class.forName
("android.app.StatusBarManager");
Method expand = statusBarManager.getMethod("disable", int.class);
expand.invoke(service, DISABLE_NONE);
} catch (Exception e) {
}
}
//屏蔽下拉
private void banStatusBar() {
int currentApiVersion = android.os.Build.VERSION.SDK_INT;
if (currentApiVersion <= 16) {
setStatusBarDisable(DISABLE_EXPAND_LOW);
} else {
setStatusBarDisable(DISABLE_EXPAND);
}
}
private void setStatusBarDisable(int disable_status) {
Object service = getSystemService("statusbar");
try {
Class<?> statusBarManager = Class.forName
("android.app.StatusBarManager");
Method expand = statusBarManager.getMethod("disable", int.class);
expand.invoke(service, disable_status);
} catch (Exception e) {
unBanStatusBar();
e.printStackTrace();
}
}
public boolean isMainThread() {
return Looper.getMainLooper() == Looper.myLooper();
}
public boolean isMainThread() {
return Looper.getMainLooper().getThread().getId() == Thread.currentThread().getId();
}
execute是执行的意思,execute()是立即执行,同步执行
enqueue是加入队列的意思,enqueue()是将任务加入线程池的队列中,异步执行
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。