EditText默认获取焦点

        <EditText
            <requestFocus/>//可获取焦点</EditText>

Gradle解决依赖冲突

gradle ModuleName:dependencies//查看依赖树状图//定位到冲突的依赖后排除
compile ('com.awesome:someawesomelibrary:1.0.0.0') {exclude group: 'com.google.android', module: 'android'
}

ListView多类型的坑

//滚动时抛出索引越界异常...
        //java.lang.ArrayIndexOutOfBoundsException: length=2; index=2//注意类型不能随便定义 范围应该为 0...getViewTypeCount-1@Overridepublic 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);//看了下,什么也没做

lv中有checkbox导致无法item点击事件无法获取焦点

cb:
android:focusable="false"
android:clickable="false"
android:focusableInTouchMode="false"
item的viewgroup中:
android:descendantFocusability="blocksDescendants"beforeDescendants:viewgroup会优先其子类控件而获取到焦点
afterDescendants:viewgroup只有当其子类控件不需要获取焦点时才获取焦点
blocksDescendants:viewgroup会覆盖子类控件而直接获得焦点

AlertDialog设置圆角背景

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实现滚动效果

//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>

Tablayout

compile 'com.android.support:design:25.3.1'
    <android.support.design.widget.TabLayoutandroid: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的gravityandroid: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() {@Overridepublic void onTabSelected(TabLayout.Tab tab) {}@Overridepublic void onTabUnselected(TabLayout.Tab tab) {}@Overridepublic 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) {@Overridepublic 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输入类型的限制

            <EditTextandroid: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() {@Overridepublic void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}@Overridepublic 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());}}@Overridepublic void afterTextChanged(Editable editable) {}});

android:ems=“10”

android:ems = "10" 设置TextView或者Edittext的宽度为10个字符的宽度。当设置该属性后,控件显示的长度就为10个字符的长度,超出的部分将不显示。

List转换成数组

String[] strings1 = datas.toArray(new String[datas.size()]);

用asynchttpclient进行文件下载

    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) {@Overridepublic void onFailure(int i, Header[] headers, Throwable throwable, File file) {Logger.d("失败"+i);}@Overridepublic void onSuccess(int i, Header[] headers, File file) {Logger.d("成功"+file.getAbsolutePath());}});}

多个mime的隐式意图

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

exlv的使用方法

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();}@Overridepublic int getGroupCount() {return mDatas != null ? mDatas.size() : 0;}@Overridepublic int getChildrenCount(int groupPosition) {return mDatas.get(groupPosition).getDatas() == null ? 0 : mDatas.get(groupPosition).getDatas().size();}@Overridepublic JsonHomeworkBean getGroup(int groupPosition) {return mDatas.get(groupPosition);}@Overridepublic JsonHomeworkBean.DatasBean getChild(int groupPosition, int childPosition) {return mDatas.get(groupPosition).getDatas().get(childPosition);}@Overridepublic long getGroupId(int groupPosition) {return groupPosition;}@Overridepublic long getChildId(int groupPosition, int childPosition) {return childPosition;}//不知道有啥用...算啦不管了@Overridepublic boolean hasStableIds() {return false;}ParentViewHolder mParentViewHolder;@Overridepublic 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;@Overridepublic 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() {@Overridepublic 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) {@Overrideprotected 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;}@Overridepublic 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);}
}

picasso压缩图片大小为控件大小

PopupWindow.update()

从当前设置状态更新弹出窗口的状态,如果当前正在显示,

PopupWindow在屏幕下方

    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();}});}}

PopupWindow和Dialog的区别

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();// 删除目录本身}

AbsListView设置item的点击效果

ablv.setSelector(new ColorDrawable(Color.TRANSPARENT));

将一个project 变成一个module

apply plugin: 'com.android.application'
改为
apply plugin: 'com.android.library'android {compileSdkVersion 25buildToolsVersion "25.0.2"defaultConfig {//删除applicationIdapplicationId "com.junx.x5demo"minSdkVersion 19targetSdkVersion 25versionCode 1versionName "1.0"testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}}
}与project的编辑版本要一致

Webview手机端设置

       //初始化WebviewwebView.loadUrl("file:///android_asset/EduMessage.html");webView.getSettings().setJavaScriptEnabled(true);WebSettings webSettings = webView.getSettings();//设置是否支持缩放webSettings.setSupportZoom(true);//开启jswebSettings.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");@JavascriptInterfacepublic void showContent() {webView.loadUrl("javascript:showContent('" + mData.getContent() + "')");}@JavascriptInterfacepublic void showTitle() {webView.loadUrl("javascript:showTitle('" + mData.getTitle() + "')");}

ListView最外部item margin失效

List中的Item的LayoutParam是直接继承自ViewPager中的LayoutParam。 不包含有margin信息。 所以在ListView中父节点设置的值会失效。

TextView设置文本过长时的省略号

            <TextViewandroid: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"/>

修改TextView的字体

.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视图上方的瞄准镜,定位到文件的位置,复制黏贴即可

ImageView加载一个文件

BitmapFactory.decodeFile(file.getAbsolutePath());

git merge 和 git merge –no-ff

git merge –no-ff 可以保存你之前的分支历史。能够更好的查看 merge历史,以及branch 状态。git merge 则不会显示 feature,只保留单条分支记录。

WebView和Html的联合调用

        //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 zoomwebSettings.setPluginState(WebSettings.PluginState.ON);//support flashwebSettings.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 {@JavascriptInterfacepublic void showContent() {webView.loadUrl("javascript:showContent('" + LogConten + "')");}@JavascriptInterfacepublic void showTitle() {webView.loadUrl("javascript:showTitle('" + LogTitle + "')");}}
//在webview中使用回调类
webView.addJavascriptInterface(new JSObjet(), "contact");

判断版本号

Build.VERSION.SDK_INT >= Build.VERSION_CODES.N

DatePickerDialog

        Calendar c = Calendar.getInstance();DatePickerDialog dialog = new DatePickerDialog(this, new DatePickerDialog.OnDateSetListener() {@Overridepublic 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() {@Overridepublic void onClick(DialogInterface dialog, int which) {}});dialog.show();

Gson解析报错:Expected BEGIN_OBJECT but was STRING at line 1 column 39 path $

  {"code":1,"info":"success","results":{"id":"1","name":"hehe"}}results对应的应该是一个实体类,如果这个时候想把他解析为String或者List就会出现异常。如果参考使用GsonForm处理后的数据模型,几乎不会出现问题;加入result后面的内容可能在请求时会因为某些原因会存在格式上的变化,这个时候就有出现该异常的风险。Gson中,关键字后面出现""引起来的内容将会被只认为是STRING,“{}”只被认为是类,“[]”只被认为是List,这个几乎是强制性的。就是说如果你的实体预计是获取String的变量,但是关键字后面对应的却出现了“{”或“[”,那么这个转换将被认为是错误的,抛出异常。解决办法:后台输出稳定的Gson格式。解决办法2:换到新版本的FastJsoncompile 'com.alibaba:fastjson:1.2.41'

用Stetho来对okhttp网络数据进行抓取

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 文件时报错has text relocations

说明编译.so文件时使用了较低版本sdk
而project 中的配置 targetSdkVersion22 大于so编译时使用的sdkversion,所以只需要把功能中
的targetSdkVersion降低即可
defaultConfig {
applicationId “com.example”
minSdkVersion 16
targetSdkVersion 22
versionCode 1
versionName “1.0”
}

SparseArray&&ArrayMap

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

为Fragment添加与Activity关联的点击事件

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;}@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);if (getArguments() != null) {mParam1 = getArguments().getString(ARG_PARAM1);mParam2 = getArguments().getString(ARG_PARAM2);}}@Overridepublic 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() {@Overridepublic void onClick(View v) {mListener.onFragmentInteraction("你好啊");}});return view;}public void onButtonPressed(String uri) {if (mListener != null) {mListener.onFragmentInteraction(uri);}}@Overridepublic void onAttach(Context context) {super.onAttach(context);if (context instanceof OnFragmentInteractionListener) {mListener = (OnFragmentInteractionListener) context;} else {throw new RuntimeException(context.toString()+ " must implement OnFragmentInteractionListener");}}@Overridepublic void onDetach() {super.onDetach();mListener = null;}public interface OnFragmentInteractionListener {void onFragmentInteraction(String uri);}
}

FragmentPagerAdapter与FragmentStatePagerAdapter

前者会将所有的Fragment缓存在内存中,后者只缓存当前item的前后各一个Fragment
简单来说前者更流畅但吃内存

在指定位置插入字符串

            StringBuffer stringBuffer = new StringBuffer(title);stringBuffer.insert(2,"\n");title=stringBuffer.toString();

android studio折叠代码

ctrl +;
ctrl -;

setDisplayHomeAsUpEnabled

//给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);

Handler跨类通讯

1.
在a类中创建一个静态的mHandler,不进行初始化
2.
在b类中创建a的实例的时候,初始化mHandler
3.
那么就可以在a类中调用mHandler,从而实现跨类通讯

listview设置有新item时自动滚动到新的item

listview.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);

获取本机wifi的ip地址

    <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();  }
}

viewpager加载时就实现pagerselected监听

//似乎是需要一点点的时间进行初始化new Timer().schedule(new TimerTask() {@Overridepublic void run() {getActivity().runOnUiThread(new Runnable() {@Overridepublic void run() {banner.getViewPager().setCurrentItem(banner.getViewPager().getCurrentItem()-1);banner.getViewPager().setCurrentItem(banner.getViewPager().getCurrentItem()+1);}});}},0);

手动实现FragmentTab

<RadioGroup><RadioButton><RadioButton>
</RadioGroup>  
radioGroup.setOnCheckedChangeListener(RadioGroup.OnCheckedChangeListener());

获取ViewPager中的子控件

在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() {@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}@Overridepublic void onPageSelected(int position) {//该控件就是当前正在展示的子控件View primaryItem = bannerAdapter.getPrimaryItem();}@Overridepublic void onPageScrollStateChanged(int state) {}});
//也可以
View view =pagerAdapter.getView(viewpager, position);
//在第三方框架rollviewpager中需要
View view =pagerAdapter.getView(viewpager, position%getRealCount());

IntentServiceDemo

作用:
1.在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统的Service相同;
2.当任务执行完后,IntentService会自动停止,而不需要我们手动去控制或stopSelf();
3.可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService中执行;
public class MyIntentService extends IntentService {//actionprivate static final String ACTION_FOO = "com.junx.nfc3.service.action.FOO";private static final String ACTION_BAZ = "com.junx.nfc3.service.action.BAZ";//用于获取参数的常量的keyprivate 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");}//主要重写该方法即可@Overrideprotected 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 Foothrow new UnsupportedOperationException("Not yet implemented");}private void handleActionBaz(String param1, String param2) {// TODO: Handle action Bazthrow 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);}
}

BindServiceDemo

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;@Overridepublic void onCreate() {mLogBinder = new LogBinder();}@Nullable@Overridepublic 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() {@Overridepublic 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);}@Overridepublic void onDestroy() {x=HAVE_BEEN_DESTROYED;}
}
    //实现ServiceConnection,用于获取binder对象public class Myconn implements ServiceConnection {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {((MyService.LogBinder) service).show(new MyService.CallBack() {@Overridepublic void onShow(final String text) {//当检测到打开其他应用后,执行相应操作mHandler.sendEmptyMessage(233);}});}@Overridepublic 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);

Android Studio自定义类似syso的模版

在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置falseprocessImg(bitmap,Uri.decode(file.toString()));while(!Flag){//循环等待}}}}

从assets中获取图片

    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();}}

Android Studio添加jniLibs目录

在module的gradle中
android {...sourceSets{main{jniLibs.srcDirs=['libs']}}
}

从Uri中获取图片

MediaStore.Images.Media.getBitmap(getApplicationContext().getContentResolver(),Uri.parse(max_id))

File.CreateNewFile();

当该文件的目录不存在时,抛出异常;
当该文件不存在时,创建该文件,返回true
当该文件存在时,返回false

Thread.interrupted()

//在线程受到阻塞时抛出一个中断信号,这样线程就得以退出阻塞的状态.
//如果线程被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() {@Overridepublic 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

        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的高度

//在listview或者gridview外部包装一层Scrollview的时候,需要动态设置设置listview的高度.使其处于内部item的与listview的高度相等public class FixedViewUtil {public static void setListViewHeightBasedOnChildren(GridView listView,int col) {// 获取listview的adapterListAdapter 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的每一个itemView 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);   }
}

ProgressBar的使用

// 方式一: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);  

解决ListView.setEmptyView()无效的问题

这个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);}

保存bitmap到本地

FileOutputStream fileOutputStream = new FileOutputStream(Environment.getExternalStorageDirectory().getPath()+ "/picture/TinyFile2Bitmap.jpg");
boolean isSuccessful = bitmap.compress(Bitmap.CompressFormat.JPEG, 20, fileOutputStream);
fileOutputStream.close();

设置TextView中字间距

android:letterSpacing="0.25"  //以一个字的宽度做比例

在DDMS的复制文件出错

[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文件不要使用中文命名

ViewGroup获取宽高的问题

View的机制决定了它无法通过getWidth获取宽高
但可以使用测量
获取测量宽高前需要先测量自身sv.measure(0,0);Log.v("meee",getClass()+":\n"+sv.getMeasuredHeight());

从相机预览帧中截取图片

    private void getPreViewImage() {mCamera.setPreviewCallback(new Camera.PreviewCallback(){@Overridepublic 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

设置statusbar透明

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);
}

FragmentTabHost的点击事件监听

mTabHost.getTabWidget().getChildTabViewAt(0).setOnClickListener(new View.OnClickListener() {  @Override  public void onClick(View v) {  }
}); 

Gson的使用

被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支持泛型

dp转px

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 1versionName "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;}

MD5工具类

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;} elsei = 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()));}
}

时间戳和date的互相转换

    //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;}    

原生JSON解析

JSONObject jsonObject = new JSONObject(k);
status = jsonObject.getInt("status");
JSONArray jsonArray = jsonObject.getJSONArray("datas");
object = jsonArray.get(i);

请求时session不匹配的问题

每次请求发现过期,但在过期时进行递归回调发现偶尔又能成功
最后发现是登陆时使用的sss.com的域名 请求时是使用的192.域名,
最后造成了这个状况

通过屏幕的宽高来修改dialog的宽高

        //设置提示框的宽高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.6p.width = (int) (d.getWidth() * 0.8); // 宽度设置为屏幕的0.65dialogWindow.setAttributes(p);

EditText和CheckBox的记忆性导致的问题

第一次加载Fragment时,给EditText赋值后,remove后,重新加载这个Fragment,并且给EditText重新赋值,可是页面上显示EditText仍然为原来的值。原因:
当fragment已存在时,重新加载会执行onViewStateRestored把原有的控件数据重新赋值回来。onViewStateRestored在onActivityCreated(Bundle)后面执行,所以onViewCreated里面的mobileEt被覆盖掉了。解决办法,重写onViewStateRestored@Overridepublic void onViewStateRestored(@Nullable Bundle savedInstanceState) {super.onViewStateRestored(savedInstanceState);mobileEt.setText(mobile);}

Recyclerview上拉加载更多

1.但在线性布局使用很合适,其他很难说
使用RecyclerView.OnScrollListener来监听RecyclerView判断上拉的时候是否滑动到底部,然后实现加载逻辑
2.三方:HeaderViewRecyclerAdapter

Recyclerview中布局的宽高参数设置无效的问题

如果item的根布局使用了linearlayout,framelayout会出现宽高都为wrap_content的问题解决:
在adapter中,@Overridepublic 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自动换行

        <TextViewandroid:maxWidth="300dp"android:singleLine="false"

旋转Bitmap的方向

    //旋转图片的方向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 {@Overridepublic 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;}

Handler清空所有任务

//清空指定任务
mHandler.removeMessages(12);
//清空所有任务
mHandler.removeCallbacksAndMessages(null);

使用FragmentTabHost时获取fragment实例

1.
String tabs[] = new String[]{"家长留言", "上课打卡", "主页", "校园信箱"};
2.for (int i = 0; i < tabs.length; i++) {//在这里传入的值就是tagTabHost.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)保存失败,发现保存时图片中不能带有:号

shape位图

<?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发送延时消息

 handler.sendEmptyMessageDelayed(MESSAGE_LOGIN,5000);handler.removeMessages(MESSAGE_LOGIN);

AlertDialog不能弹出输入法

    public class SettingPop extends AlertDialog{protected SettingPop(@NonNull Context context) {super(context);}@Overrideprotected 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);}}

Android Studio制作9patch图

右键一张png图片,Create 9Patch file
双击生成的9.图,选择拉伸区域注:9.必须放在drawable目录下,否则报错
后缀必须为.9.png
左上为拉伸区域,右下为文字显示区域

eclipse

添加自定义类库作为依赖

1.将类库导入到adt中

import project

2.添加类库作为依赖

右键project
properties
Android>>library>>add apply

添加兼容包

下载到compat包
复制到lib下...就是这么简单

导入项目乱码文题

右键project
properties
修改编码格式,一般是UTF-8 GBK

Android Studio

Plugin Error

将错误提示滚动到最后
点击Enable support
会弹出是否restart 点击是等待其重启启动后即可

迁移Eclipse项目至Android Studio

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

Eclipse生成apk

右键project Android Tools
Export Singed Apk
选择要生成apk的project
输入两次密码

ListView动态高度

wrap_content即可

提示找不到Header类

api23后,google移除了某些类
可以通过导入jar包的方式解决

Android Studio导入Eclipse项目运行乱码

一般是由于编码格式错误引起的
可以在module 的gradle中修改
android {compileSdkVersion 26buildToolsVersion "25.0.3"android {compileOptions.encoding = "gbk"}//添加这一行,强制运行时的编码格式
但设置修改的编码格式是全局的
也可以修改某一个文件的编码格式
在android studio的右下角,可以设置编码格式
CRLF>>relode 是以不同的编码格式重新打开   convert:是以当前的文本更改代码格式为选中的编码格式 

Error:Error: This fragment should provide a default constructor (a public constructor with no arguments) (com.ct.parentipa.fragment.MianFragment) [ValidFragment]

为该Fragment提供一个默认的空构造器

添加多个注解

@SuppressLint("ResourceAsColor,ValidFragment")

提示This fragment should provide a default constructor (a public constructor with no arguments) (com.example.TestFragment)

意思是应该使用bundle来传递函数
可以使用两种方法解决
1.修改形参,使用bundle传递数据
2.添加注解
@SuppressLint("ValidFragment")
public class PhotoFragment extends MyBaseFragment {

SimpleDateFormat

    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");//2017-08-28Date 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

Android Studio混淆

生成签名的apk
build >generate Signed Apk>输入两次密码
基本混淆模版
在module的build.gradle
android {......buildTypes {release {//开启混淆minifyEnabled true// Zipalign优化zipAlignEnabled true// 移除无用的resource文件shrinkResources true//第一个是系统默认的基本混淆,第二个是自定义的混淆PLUSproguardFiles 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:52aga
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

Fresco的使用

是一款控件级别的图片加载框架
//导包
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.后来还发现可能是模拟器的时间没有校准解决办法:使用单例模式来封装请求框架,校准

fastJson用法

阅读别人的代码的方法

按照生命周期依次读一遍,尽量弄懂每个方法的意思,再阅读点击事件
然后再读一遍

picasso用法

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

Fiddler的用法

1.获取fiddler的端口号
Tool>>Fiddler Options>>connections 2.获取本地的ip地址
alt+r>>cmd>>ipconfig3.在模拟器中网络 >>详细设置中设置ip和端口号注意如果fiddler没有打开||本地模拟器改变,那么模拟器是无法上网的,所用用完要把模拟器设置回去

Android Studio 版本控制后文件名称颜色的含义

绿色,已经加入控制暂未提交
红色,未加入版本控制
蓝色,加入,已提交,有改动
白色,加入,已提交,无改动
灰色:版本控制已忽略文件。

自定义代码模版

Setttings>>Live Templates
选中android
就可以自定义自己的代码模版了

Async_http请求网络框架的使用

1.导包
repositories {mavenCentral()
}dependencies {compile 'com.loopj.android:android-async-http:1.4.9'
}2.post请求使用方法
public class AsyncHttpAsynchttpUtil {
//final单例模式,让请求带上cookiesstatic 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() {@Overridepublic void onFailure(int arg0, Header[] arg1, byte[] arg2,Throwable arg3) {//arg0是响应码}@Overridepublic void onSuccess(int arg0, Header[] arg1, byte[] arg2) {//arg2是数据流String result = new String(arg2);//通过接口进行回调loadListener.OnFinish(list, status);}});}
}

ZoomImageView(手势缩放图片框架)

github:
https://github.com/sephiroth74/ImageViewZoom1.导包
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);

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 filemediaScanIntent.setData(contentUri);context.sendBroadcast(mediaScanIntent);} else {context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,Uri.parse("file://" + Environment.getExternalStorageDirectory())));}Toast.makeText(context, "保存成功", 1).show();}

LinearLayout线性布局的时候异常

marginTop和marginBottom的问题
当两个相冲突的时候,不确定哪个发生作用
特别注意两个控件的margin相冲的时候

Bitmap的压缩

图片质量压缩: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;  }  

HashMap高效率遍历

      //只需要遍历一次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);}

ViewPager+Fragment遇到的一个oom异常

有个坑,如果fragment的oncreatview的中inflater生成的view与父控件绑定的话,会oom

AndroidStudio创建位图

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};

Caused by: android.view.InflateException: Binary XML file line #57: Error inflating class android.support.design.widget.FloatingActionButton

发现不使用backgroundTint便不会报错在xml里面得用app:backgroundTint="@color/red"才有效果,不能用android:backgroundTint.
前面要加上命名空间xmlns:app="http://schemas.android.com/apk/res-auto"

设置无标题

requestWindowFeature(Window.FEATURE_NO_TITLE);

Sdk版本适配

android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP

!!! JUnit version 3.8 or later expected:

添加两个依赖// Required -- JUnit 4 frameworktestCompile 'junit:junit:4.12'// Optional -- Mockito frameworktestCompile 'org.mockito:mockito-core:1.10.19'

java.lang.RuntimeException: Method setUp in android.test.AndroidTestCase not mocked

然后又显示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);}
}

建议ignore

Android Studio 中建议过滤的文件:
- .idea 文件夹
- .gradle 文件夹
- 所有的 build 文件夹
- 所有的 .iml 文件
- local.properties 文件

Cursor的使用方法

    //通过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());}}

json的原生解析

                    JSONObject jsonObject = new JSONObject(k);status = jsonObject.getInt("status");

Math.pow(2.0D, i);

//次方,第一个参数是底数,第二个参数是次方数

options.inJustDecodeBounds

options.inJustDecodeBounds = true 表示只读图片,不加载到内存中,设置这个参数为true,就不会给图片分配内存空间,但是可以获取到图片的大小等属性; 设置为false, 就是要加载这个图片.设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度

options.inSampleSize

//设置缩小倍数,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}}

判断sd卡的挂载状态

        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;  }  }
}

Semaphore的使用

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();  }
}

LruCache的使用

// 获取应用的最大可用内存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();}};

子线程和looper的使用

        // 后台轮询线程mPoolThread = new Thread() {@Overridepublic void run() {Looper.prepare();//todoLooper.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;}

获取ImagrView的宽高

    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;}

通过反射获取imageview的属性值

    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);}

将Byte[]转换成2位16进制

    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的大小设置为4mint maxsize = 4 * 1024 * 1024;lruCache = new LruCache<String, Bitmap>(maxsize) {@Overrideprotected 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中取bmpprivate 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;}@Overrideprotected 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;}@Overrideprotected 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 stubif (!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;}}
}

MD5工具类

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;} elsei = 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()));}
}

StreamUtils

public class StreamUtil {//把inputStrem转换为Stringpublic 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;}
}

自定义控件:可缩放的imageview

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(){@Overridepublic 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;}}@Overridepublic 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")@Overridepublic 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;}@Overridepublic boolean onScaleBegin(ScaleGestureDetector detector){return true;}@Overridepublic void onScaleEnd(ScaleGestureDetector detector){}//触摸事件的监听@Overridepublic 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];}@Overrideprotected void onAttachedToWindow(){super.onAttachedToWindow();getViewTreeObserver().addOnGlobalLayoutListener(this);}@SuppressWarnings("deprecation")@Overrideprotected void onDetachedFromWindow(){super.onDetachedFromWindow();getViewTreeObserver().removeGlobalOnLayoutListener(this);}@Overridepublic 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);

删除module

在setting中打开project struct
点击要删除的module
点击左上方的-号
ok以project打开项目
右键需要删除的module

Android Studio中添加so库

在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文件了

Debug

在需要检查的代码开头和结尾打上断点
右键 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的使用

<style name="xx"><item name="textsize">12sp<><item name=textColor>...
</style>2.在布局中引用样式
<TvStyle="@style/xx">
注意和android:textStyle的区别,用错了会崩溃

将app设置为大内存

配置文件中:
<application android:largelHeap="true"

sdk版本适配

if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP)

延时的message

 //发送延时的message给handler                    mHandler.sendEmptyMessageDelayed(MESSAGE_SCROLL_TO,DELAYED_TIME);

对gravity的理解

gravity失效,因为gravity作用域内容,layoutgravity才是作用于控件在父控件中的位置的

设置app的方向

<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()中屏蔽下拉效果@Overridepublic 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();
}

Okhttp的execute()enqueue()

execute是执行的意思,execute()是立即执行,同步执行
enqueue是加入队列的意思,enqueue()是将任务加入线程池的队列中,异步执行

日常工作中遇到的那些坑相关推荐

  1. c++读取utf8文件_经常在日常工作中处理统一码文件(or其他编码)?这篇必读

    全文共2717字,预计学习时长5分钟 对于那些经常在日常工作中处理统一码文件(也适用于其他编码)的人来说,这篇文章是必读的.对于自然语言处理的从业者,处理统一码文件是一场噩梦,尤其是使用Windows ...

  2. 日常工作中,软件测试人员如何避免“背锅”

    作为一名软件测试工程师,日常工作中最常打交道的肯定就是开发和产品经理.有沟通就会问题,有问题难免会有争执.那么你肯定听过这些话: "这么弱智的bug你都测不出来吗?" " ...

  3. 业务团队如何在日常工作中做稳定性?涵盖事前、事中、事后的方方面面

    你好呀,我是Bella酱- "又不是不能用,能用就行.""又不是不能跑,能跑就行.程序和人有一个能跑就行." 相信很多同学都听过这2句话.乍听没毛病.编程3部曲 ...

  4. 大华视频服务器系统日志怎么看,日常工作中查看工控机Windows日志的方法

    原标题:日常工作中查看工控机Windows日志的方法 工控机Windows日志位于工控机管理的事件查看器中,主要是用于存储来自应用程序以及整个系统的文件.一般可以分为应用程序日志.安全日志.系统日志这 ...

  5. 办公室计算机知识论文,办公室日常工作中办公自动化的运用-计算机应用技术论文-计算机论文.docx...

    办公室日常工作中办公自动化的运用-计算机应用技术论文-计算机论文 --文章均为WORD文档,下载后可直接编辑使用亦可打印-- 摘 要: 办公室管理是企业发展的重要组成部分, 传统办公室管理需使用大量的 ...

  6. [工作中爬过的坑] Kafka配置域名的三种难度

    文章目录 1. 背景说明 2. 初级难度 - 无认证Kafka 3. 中级难度 - SASL/PLAIN认证Kafka 4. 有人捣乱的难度 - Ambari中SASL/PLAIN认证Kafka 我曾 ...

  7. RIP 此篇用来记录日常工作中使用到的正则表达式

    在工作中偶尔会使用到正则表达式,  每次用到之后都是上网找,  太浪费时间了, 所以此贴专门用于收录日常工作中使用到的正则表达式 ( 不要问我为什么不自己学学正则表达式,   因为: lan ) 用心 ...

  8. 日常工作中的几个excel小技巧

    大家好!我是xyz,又和大家见面了!今天分享几个日常工作中经常使用的小技巧,希望对大家能有所帮助. Ctrl+\的用法 对两列或是多列数据进行核对,方法有很多,今天介绍的是一组快捷键,只需要1秒钟就搞 ...

  9. 如何在日常工作中提升技术能力

    如何在日常工作中提升技术能力 相信我们很多工程师在工作中做的最多的就是CRUD的任务,可能很多同学觉得这些工作不会有成长的机会或无法提升,其实这些大部分都是眼高手低的心里,CRUD也可以学到更多.做到 ...

最新文章

  1. HTML 标签包含规范,规避脱标流,图片和文字垂直居中对齐,
  2. shell中循环安装软件包
  3. 有理数加减乘除 计算机应用带答案,列50道有理数的混合运算(加减乘除)包括答案 初一的...
  4. Beanutils.copyProperties复制参数不为null的属性
  5. 高德地图定位误差_【“怼”上了,四川景区一度建议别用高德地图】导航定位错误引用户到封闭区域,致拥堵!高德地图道歉,已更正!...
  6. Java基础--通过反射获取私有的成员方法示例代码
  7. 【spring boot】使用RestTemplate调用微信code2Session接口
  8. 抽取大小: 高斯sigma_无服务器:SLAppForge Sigma入门
  9. 四旋翼无人机调研结果
  10. 如何下载linux历史版本下载,CentOS历史版本下载方法
  11. 下一个十年:练好内功被集成的弹性计算
  12. Vim 可视化模式入门
  13. 布局设置-Meta标签 and Media(来自bootstrap)
  14. 解决标签回车后产生的空格2
  15. mysql的驱动jar包_各版本MySQL数据库驱动程序jar包大全(java连接mysql驱动jar包)
  16. Linux_zlog日志系统的安装与使用
  17. 禅道管理员忘记密码找回密码
  18. 图像处理之相似图片识别(直方图应用篇)
  19. Latex输入分段函数
  20. 5分钟快速撑起高校邮件保护伞

热门文章

  1. 数据查询和业务流分开_滴滴实时数仓逐层剖解:实时与离线数据误差0.5%
  2. 利用Python绘制一个爱心
  3. gateway资源详解
  4. TMS Workflow Studio2.12框架,用户也可以创建工作流
  5. HTTP Status 404错误分析及解决方法
  6. java 四分位距算法和标准差
  7. 英语语法汇总(7.介词)
  8. python基础 判断题
  9. FFMPEG学习----解码视频
  10. 如何租用云服务器并进行远程连接