日常工作中遇到的那些坑

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
        @Override
        public int getItemViewType(int position) {
            DataItem dataItem = map.get(position);
            return dataItem!=null?0:1;
        }

复制文件

    //复制文件
    private void copyFile(String oldPath, String newPath) {
        try {
            int bytesum = 0;
            int byteread = 0;
            File oldfile = new File(oldPath);
            if (oldfile.exists()) { //文件不存在时
                InputStream inStream = new FileInputStream(oldPath); //读入原文件
                FileOutputStream fs = new FileOutputStream(newPath);
                byte[] buffer = new byte[1444];
                int length;
                while ((byteread = inStream.read(buffer)) != -1) {
                    bytesum += byteread; //字节数 文件大小
                    //System.out.println(bytesum);
                    fs.write(buffer, 0, byteread);
                }
                inStream.close();
            }
        } catch (Exception e) {
            System.out.println("复制单个文件操作出错");
            e.printStackTrace();

        }
    }

通过一个像素点进行进程保活

        //通过一个像素点进行进程保活,被万恶的腾讯QQ带坏了
        windowManager = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
        surfaceView = new SurfaceView(this);
        mSurfaceHolder = surfaceView.getHolder();
        WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
                1, 1,
                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                PixelFormat.TRANSLUCENT
        );
        layoutParams.gravity = Gravity.LEFT | Gravity.TOP;//放在左上角
        windowManager.addView(surfaceView, layoutParams);
        mSurfaceHolder.addCallback(this);//看了下,什么也没做

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.TabLayout
        android:id="@+id/tablayout_orderfood_act"
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:layout_marginTop="0dp"
        app:tabIndicatorColor="#3af"//指示器颜色
        app:tabSelectedTextColor="#000"//选中后文字颜色
        app:tabTextColor="#000"//tab中文字颜色
        app:tabMode="fixed"//是否固定
        app:tabGravity="center"//tab的gravity

        android:background="#fff" app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/linearLayout3"/>
        tab_ll.addTab(tab_ll.newTab().setText("今日菜单"));
        tab_ll.addTab(tab_ll.newTab().setText("我的订餐"));
                tab_ll.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });
        ArrayList<String> datas=new ArrayList<>();
        for (int i = 0; i < 2; i++) {
            datas.add("哈哈"+i);
        }
        ArrayList<CharSequence> titles=new ArrayList<>();
        titles.add("今日菜单");
        titles.add("我的订餐");
        vp.setAdapter(new CommonPagerAdapter<String>(OrderFoodMainActivity.this,datas,titles) {
            @Override
            public View getView(ViewGroup container, String data, int position) {
                View view = LayoutInflater.from(mContext).inflate(R.layout.pop_scoretype, container, false);
                return view;
            }
        });
        tab_ll.setupWithViewPager(vp);

EditText输入类型的限制

            <EditText
                android:id="@+id/editText_username"
                android:layout_width="0dp"
                android:layout_height="30dp"

               //通过属性, android:digits中的内容才能被输入
             android:digits=
             "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
                android:layout_weight="1"
                android:background="@color/white"
                android:inputType="text"
                android:ems="10"
                android:hint="账 号"
                android:padding="5dp"
                android:textSize="13dp">
            </EditText>
//使用正则来过滤
        et.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                String content=et.getText().toString();
                String regEx="[^a-zA-Z0-9]";
                Pattern pattern = Pattern.compile(regEx);
                Matcher matcher = pattern.matcher(content);
                String trimedContent = matcher.replaceAll("").trim();
                if (!content.equals(trimedContent)){
                    et.setText(trimedContent);
                    et.setSelection(trimedContent.length());
                }

            }

            @Override
            public void afterTextChanged(Editable editable) {

            }
        });

android:ems=“10”

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

            @Override
            public void onSuccess(int i, Header[] headers, File file) {
                Logger.d("成功"+file.getAbsolutePath());
            }
        });
    }

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

    @Override
    public int getGroupCount() {
        return mDatas != null ? mDatas.size() : 0;
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        return mDatas.get(groupPosition).getDatas() == null ? 0 : mDatas.get(groupPosition).getDatas().size();
    }

    @Override
    public JsonHomeworkBean getGroup(int groupPosition) {
        return mDatas.get(groupPosition);
    }

    @Override
    public JsonHomeworkBean.DatasBean getChild(int groupPosition, int childPosition) {
        return mDatas.get(groupPosition).getDatas().get(childPosition);
    }

    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    //不知道有啥用...算啦不管了
    @Override
    public boolean hasStableIds() {
        return false;
    }

    ParentViewHolder mParentViewHolder;

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = LayoutInflater.from(mContext).inflate(R.layout.exlv_parent_item_homework_message, parent, false);
            mParentViewHolder = new ParentViewHolder(convertView);
            convertView.setTag(mParentViewHolder);
        } else {
            mParentViewHolder = (ParentViewHolder) convertView.getTag();
        }
        JsonHomeworkBean jsonHomeworkBean = mDatas.get(groupPosition);
        if (jsonHomeworkBean.getStatus() == 1) {
            mParentViewHolder.count.setText(jsonHomeworkBean.getDatas().size() + "");
            mParentViewHolder.title.setText(jsonHomeworkBean.getClassName());
        }
        return convertView;
    }

    ChildViewHolder mChildViewHolder;

    @Override
    public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = LayoutInflater.from(mContext).inflate(R.layout.exlv_child_homework_message, parent, false);
            mChildViewHolder = new ChildViewHolder(convertView);
            convertView.setTag(mChildViewHolder);
        } else {
            mChildViewHolder = (ChildViewHolder) convertView.getTag();
        }
        JsonHomeworkBean.DatasBean datasBean = mDatas.get(groupPosition).getDatas().get(childPosition);
        if (datasBean == null)
            return convertView;
        List<String> imgList = datasBean.getImgList();
        final int id = datasBean.getId();
        mChildViewHolder.teacherName.setText(datasBean.getT_name());
        mChildViewHolder.subjectName.setText(datasBean.getSubject_name());
        mChildViewHolder.homeworkContent.setText(datasBean.getContent());
        mChildViewHolder.time.setText(TimeUtils.getLocalTimeString(datasBean.getCreate_date().getTime()));
        mChildViewHolder.delete.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mDeleteCallback!=null)
                    mDeleteCallback.delete(id);

            }
        });
        mChildViewHolder.pics.setAdapter(
                new HolderAdapter<String, CommonViewHolder2>(mContext, imgList, R.layout.item_gv_single_iv) {
                    @Override
                    protected void bindDatas(CommonViewHolder holder, String data, int position) {
                        ImageView iv=holder.getView(R.id.iv_single_item);
                        String url = AsyncHttpAsynchttpUtil.uhtp + "SchoolPC/res/homeworks/" + data;
                        Picasso.with(mContext)
                                .load(url)
                                .fit()
                                .into(iv);
                    }
                });
        FixedViewUtil.setListViewHeightBasedOnChildren(mChildViewHolder.pics, 3);
        return convertView;
    }

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return false;
    }

    static class ParentViewHolder {
        ImageView iv;
        TextView title;
        TextView count;

        public ParentViewHolder(View rootView) {
            iv = (ImageView) rootView.findViewById(R.id.iv_hint_homework_message_act_exlvparent);
            title = (TextView) rootView.findViewById(R.id.tv_title_homework_message_act_exlvparent);
            count = (TextView) rootView.findViewById(R.id.tv_count_homework_message_act_exlvparent);
        }
    }

    static class ChildViewHolder {
        TextView subjectName;
        TextView teacherName;
        TextView delete;
        TextView homeworkContent;
        GridView pics;
        TextView time;

        public ChildViewHolder(View rootView) {
            subjectName = (TextView) rootView.findViewById(R.id.tv_subject_name);
            teacherName = (TextView) rootView.findViewById(R.id.tv_teacher_name);
            delete = (TextView) rootView.findViewById(R.id.tv_delete);
            homeworkContent = (TextView) rootView.findViewById(R.id.tv_homework_content);
            pics = (GridView) rootView.findViewById(R.id.gv_homework_pictures);
            time = (TextView) rootView.findViewById(R.id.tv_time);
        }
    }
    public interface deleteCallback{
        void delete(int deleteId);
    }
}

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 25
    buildToolsVersion "25.0.2"
    defaultConfig {
    //删除applicationId
        applicationId "com.junx.x5demo"
        minSdkVersion 19
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

与project的编辑版本要一致

Webview手机端设置

       //初始化Webview
        webView.loadUrl("file:///android_asset/EduMessage.html");
        webView.getSettings().setJavaScriptEnabled(true);

        WebSettings webSettings = webView.getSettings();
        //设置是否支持缩放
        webSettings.setSupportZoom(true);
        //开启js
        webSettings.setJavaScriptEnabled(true);
        //设置打开时js可以被打开
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
        //是否使用内置的缩放机制
        webSettings.setBuiltInZoomControls(true);
        //是否开启插件
        webSettings.setPluginState(WebSettings.PluginState.ON);
        //是否使用标记的中宽高
        webSettings.setUseWideViewPort(true);
        //设置是否考虑到屏幕宽高
        webSettings.setLoadWithOverviewMode(true);
        webSettings.setTextSize(WebSettings.TextSize.LARGEST);

        DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
        int mDensity = metrics.densityDpi;
        if (mDensity == 240) {
            webSettings.setDefaultZoom(ZoomDensity.FAR);
        } else if (mDensity == 160) {
            webSettings.setDefaultZoom(ZoomDensity.MEDIUM);
        } else if (mDensity == 120) {
            webSettings.setDefaultZoom(ZoomDensity.CLOSE);
        } else if (mDensity == DisplayMetrics.DENSITY_XHIGH) {
            webSettings.setDefaultZoom(ZoomDensity.FAR);
        } else if (mDensity == DisplayMetrics.DENSITY_TV) {
            webSettings.setDefaultZoom(ZoomDensity.FAR);
        }
        webView.addJavascriptInterface(this,"contact");

    @JavascriptInterface
    public void showContent() {
        webView.loadUrl("javascript:showContent('" + mData.getContent() + "')");
    }
    @JavascriptInterface
    public void showTitle() {
        webView.loadUrl("javascript:showTitle('" + mData.getTitle() + "')");
    }

ListView最外部item margin失效

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

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

            <TextView
                android:id="@+id/tv_content_edu_message_item"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:ellipsize="end"//...在末尾
                android:maxLines="1"
                android:text="content"
                android:textSize="13dp"
            />

修改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 mergeno-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 zoom
        webSettings.setPluginState(WebSettings.PluginState.ON);//support flash
        webSettings.setUseWideViewPort(true);// 这个很关键
        webSettings.setLoadWithOverviewMode(true);
        webSettings.setTextSize(WebSettings.TextSize.LARGEST);

        DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
        int mDensity = metrics.densityDpi;
        if (mDensity == 240) {
            webSettings.setDefaultZoom(ZoomDensity.FAR);
        } else if (mDensity == 160) {
            webSettings.setDefaultZoom(ZoomDensity.MEDIUM);
        } else if (mDensity == 120) {
            webSettings.setDefaultZoom(ZoomDensity.CLOSE);
        } else if (mDensity == DisplayMetrics.DENSITY_XHIGH) {
            webSettings.setDefaultZoom(ZoomDensity.FAR);
        } else if (mDensity == DisplayMetrics.DENSITY_TV) {
            webSettings.setDefaultZoom(ZoomDensity.FAR);
        }
<html>
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
        <script type="text/javascript">
        <!--第一步,在Html中定义js方法-->
            function showContent(jsondata){
            alert(title);
             document.getElementById("personts").innerHTML=jsondata;
            }
            function showTitle(jsondata){
            alert(title);
             document.getElementById("title").innerHTML=jsondata;
            }
        </script>
        <!--修正图片尺寸,设置宽度最大值,高度自适应防变形-->
        <style>img{max-width:100% !important; height:auto !important;}</style>
    </head>
    <!--在加载网页时,调用js的两个方法-->
    <body onload="javascript:contact.showContent();javascript:contact.showTitle()" bgcolor="#efeff4">
        <!--白色圆角背景-->
        <div style=" background-color:white; border-radius:10px; margin:8px; padding-left:10px; padding-right:10px; padding-top:5px; padding-bottom:5px; box-shadow:3px 3px 2px 2px lightgray; ">
            <!--标题-->
            <p id="title" style="font-size:0.8em;text-align: center; color:#2191FB; margin:0px;" >
            </p>
            <!--横线-->
            <div  style="background-color:#efeff4; width:100%; height:1px; margin-top:5px; margin-bottom:5px;"></div>
            <div style="font-size:0.5em;" id="personts"></div>
        </div>
    </body>
</html>
    //在java中定义回调类,调用js中方法
    public final class JSObjet {
        @JavascriptInterface
        public void showContent() {

            webView.loadUrl("javascript:showContent('" + LogConten + "')");
        }
        @JavascriptInterface
        public void showTitle() {
            webView.loadUrl("javascript:showTitle('" + LogTitle + "')");
        }
    }
//在webview中使用回调类
webView.addJavascriptInterface(new JSObjet(), "contact");

判断版本号

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

DatePickerDialog

        Calendar c = Calendar.getInstance();
        DatePickerDialog dialog = new DatePickerDialog(this, new DatePickerDialog.OnDateSetListener() {
            @Override
            public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
                month+=1;//因为它是从0开始计算的
            }
        }, c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH));
        dialog.setTitle("请选择");
        dialog.setCanceledOnTouchOutside(true);
        dialog.setCancelable(true);
        dialog.setButton(DialogInterface.BUTTON_NEGATIVE, "取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {

            }
        });
        dialog.show();

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:换到新版本的FastJson
         compile '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,因为它避免了自动装箱的过程,如果keylong类型,它还提供了一个LongSparseArray来确保keylong类型时的使用

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

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mParam1 = getArguments().getString(ARG_PARAM1);
            mParam2 = getArguments().getString(ARG_PARAM2);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_blank, container, false);
        View fl = view.findViewById(R.id.fl);
        int i = new Random().nextInt(5);
        int color=0;
        switch (i){
            case 0:
                color= Color.RED;
                break;
            case 1:
                color=Color.BLUE;
                break;
            case 2:
                color=Color.GREEN;
                break;
            case 3:
                color=Color.YELLOW;
                break;
            case 4:
                color=Color.BLACK;
                break;
            case 5:
                color=Color.GRAY;
                break;
        }
        fl.setBackgroundColor(color);
        View btn = view.findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mListener.onFragmentInteraction("你好啊");
            }
        });
        return view;
    }

    public void onButtonPressed(String uri) {
        if (mListener != null) {
            mListener.onFragmentInteraction(uri);
        }
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof OnFragmentInteractionListener) {
            mListener = (OnFragmentInteractionListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement OnFragmentInteractionListener");
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }

    public interface OnFragmentInteractionListener {
        void onFragmentInteraction(String uri);
    }
}

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() {
            @Override
            public void run() {
                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        banner.getViewPager().setCurrentItem(banner.getViewPager().getCurrentItem()-1);
                        banner.getViewPager().setCurrentItem(banner.getViewPager().getCurrentItem()+1);
                    }
                });
            }
        },0);

手动实现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() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
            //该控件就是当前正在展示的子控件
                View primaryItem = bannerAdapter.getPrimaryItem();
            }


            @Override
            public void onPageScrollStateChanged(int state) {
            }
        });
//也可以
View view =pagerAdapter.getView(viewpager, position);
//在第三方框架rollviewpager中需要
View view =pagerAdapter.getView(viewpager, position%getRealCount());

IntentServiceDemo

作用:
1.在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统的Service相同;
2.当任务执行完后,IntentService会自动停止,而不需要我们手动去控制或stopSelf();
3.可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService中执行;
public class MyIntentService extends IntentService {
    //action
    private static final String ACTION_FOO = "com.junx.nfc3.service.action.FOO";
    private static final String ACTION_BAZ = "com.junx.nfc3.service.action.BAZ";
    //用于获取参数的常量的key
    private static final String EXTRA_PARAM1 = "com.junx.nfc3.service.extra.PARAM1";
    private static final String EXTRA_PARAM2 = "com.junx.nfc3.service.extra.PARAM2";

    public MyIntentService() {
        super("MyIntentService");
    }

    //主要重写该方法即可
    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent != null) {
            //先获取action,进行判断
            final String action = intent.getAction();
            if (ACTION_FOO.equals(action)) {
                //获取参数,进行相应操作
                final String param1 = intent.getStringExtra(EXTRA_PARAM1);
                final String param2 = intent.getStringExtra(EXTRA_PARAM2);
                handleActionFoo(param1, param2);
            } else if (ACTION_BAZ.equals(action)) {
                final String param1 = intent.getStringExtra(EXTRA_PARAM1);
                final String param2 = intent.getStringExtra(EXTRA_PARAM2);
                handleActionBaz(param1, param2);
            }
        }
    }
    //业务逻辑
    private void handleActionFoo(String param1, String param2) {
        // TODO: Handle action Foo
        throw new UnsupportedOperationException("Not yet implemented");
    }
    private void handleActionBaz(String param1, String param2) {
        // TODO: Handle action Baz
        throw new UnsupportedOperationException("Not yet implemented");
    }
    //也可以写一个方法,给予act调用
    public static void startSomeTask(Context context,String action,String params1,String params2){
        Intent intent = new Intent(context,MyIntentService.class);
        intent.setAction(action);
        intent.putExtra(EXTRA_PARAM1,params1);
        intent.putExtra(EXTRA_PARAM2,params2);
        context.startService(intent);
    }
}

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;

    @Override
    public void onCreate() {
        mLogBinder = new LogBinder();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mLogBinder;

    }
    //获取最近打开的包的应用的名字
    public String getApplicationStatus() {
        SystemClock.sleep(1000);
        if (x!=0){
            return "sdfs";
        }
        UsageStatsManager mUsageStatsManager = (UsageStatsManager)getApplicationContext().getSystemService(Context.USAGE_STATS_SERVICE);
        long time = System.currentTimeMillis();
        List<UsageStats> stats ;
        stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time-60*60*1000, time);
        if(stats != null) {
            TreeMap<Long,UsageStats> mySortedMap = new TreeMap<Long,UsageStats>();
            for (UsageStats usageStats : stats) {
                mySortedMap.put(usageStats.getLastTimeUsed(),usageStats);
            }
            if(mySortedMap != null && !mySortedMap.isEmpty()) {
                UsageStats usageStats = mySortedMap.get(mySortedMap.lastKey());
                usageStats.getPackageName();
                String packageName = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
                return packageName;
            }
        }
        return null;
    }


    Thread thread;
    int x=0;
    public class LogBinder extends Binder{
        public void show(final CallBack callBack){
             thread= new Thread(new Runnable() {
                @Override
                public void run() {
                    //当线程退出时终止循环
                    F:while(x!=HAVE_BEEN_DESTROYED){
                        String name = getApplicationStatus();
                        //如果最近打开的应用的包名不是以下的三个,则退出死循环
                        if (!name.equals("com.junx.mycircleview")&&!name.equals("com.android.launcher3")
                                &&!name.equals("com.android.systemui"))
                            break F;
                    }
                    if (x!=HAVE_BEEN_DESTROYED){
                        Log.v("meee","检测到打开了别的应用");
                        callBack.onShow("");
                    }
                }
            });
            thread.start();
        }
    }

    //监听数据回调
    public interface CallBack{
        void onShow(String text);
    }


    @Override
    public void onDestroy() {
        x=HAVE_BEEN_DESTROYED;
    }
}
    //实现ServiceConnection,用于获取binder对象
    public class Myconn implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            ((MyService.LogBinder) service).show(new MyService.CallBack() {
                @Override
                public void onShow(final String text) {
                    //当检测到打开其他应用后,执行相应操作
                    mHandler.sendEmptyMessage(233);
                }
            });
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    }
//绑定操作
intent = new Intent(this, MyService.class);
conn = new Myconn();
bindService(intent, conn, BIND_AUTO_CREATE);

打开有使用权限的设置界面

Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
        startActivity(intent);

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置false
                    processImg(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() {
            @Override
            public void onClick(DialogInterface dialog, int item) {
                boolean result= Utility.checkPermission(Videocmp.this);
                if (items[item].equals("拍照")) {
                    if(result)
                        cameraIntent();
                } else if (items[item].equals("图库")) {
                    if(result)
                        galleryIntent();
                } else if (items[item].equals("Cancel")) {
                    dialog.dismiss();
                }
            }
        });
        builder.show();

对于时间的操作

//保存时间做变量
Long mTime=System.currentTimeMills();
//前一天
mTime=mTime-(1000*60*60*24);

手动绘制bitmap

        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的adapter
        ListAdapter listAdapter = listView.getAdapter();
        if (listAdapter == null) {
            return;
        }
        // 固定列宽,有多少列
        int totalHeight = 0;
        // i每次加4,相当于listAdapter.getCount()小于等于4时 循环一次,计算一次item的高度,
        // listAdapter.getCount()小于等于8时计算两次高度相加
        for (int i = 0; i < listAdapter.getCount(); i += col) {
            // 获取listview的每一个item
            View listItem = listAdapter.getView(i, null, listView);
            listItem.measure(0, 0);
            // 获取item的高度和
            totalHeight += listItem.getMeasuredHeight();
            totalHeight += listView.getVerticalSpacing();
            if (i==listAdapter.getCount()-1) {
                totalHeight += listView.getVerticalSpacing();
            }
        }
        // 获取listview的布局参数
        ViewGroup.LayoutParams params = listView.getLayoutParams();
        // 设置高度
        params.height = totalHeight;
        // 设置margin
        ((MarginLayoutParams) params).setMargins(10, 10, 10, 10);
        // 设置参数
        listView.setLayoutParams(params);
    }

    public static void setListViewHeightBasedOnChildren(ListView lv){  
        ListAdapter listAdapter = lv.getAdapter();
        int listViewHeight = 0;  
        int adaptCount = listAdapter.getCount();  
        for(int i=0;i<adaptCount;i++){  
            View temp = listAdapter.getView(i,null,lv);  
            temp.measure(0,0);  
            listViewHeight += temp.getMeasuredHeight();  
        }  
        LayoutParams layoutParams = lv.getLayoutParams();  
        layoutParams.width = LayoutParams.MATCH_PARENT;  
        layoutParams.height = listViewHeight;  
        lv.setLayoutParams(layoutParams);  
    }
}
//也可以自定义gridview,使其占满最大
public class MyGridView extends GridView{  
    public MyGridView(Context context, AttributeSet attrs) {   
        super(context, attrs);   
    }   

    public MyGridView(Context context) {   
        super(context);   
    }   

    public MyGridView(Context context, AttributeSet attrs, int defStyle) {   
        super(context, attrs, defStyle);   
    }   

    @Override   
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {   
        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
                MeasureSpec.AT_MOST);   
        super.onMeasure(widthMeasureSpec, expandSpec);   
    }   
}

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(){

            @Override
            public void onPreviewFrame(byte[] data, Camera camera) {
                Camera.Size size = camera.getParameters().getPreviewSize();
                try{
                    YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
                    if(image!=null){
                        ByteArrayOutputStream stream = new ByteArrayOutputStream();
                        image.compressToJpeg(new Rect(0, 0, size.width, size.height), 80, stream);

                        Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
                        int i = bmp.getRowBytes() * bmp.getHeight() / 1024;

                        iv_student1.setImageBitmap(bmp);
                        stream.close();
                        mCamera.setPreviewCallback(null);
                    }
                }catch(Exception ex){
                    Log.e("Sys","Error:"+ex.getMessage());
                }
            }
        });
    }

分割线的问题

因为View中没有重写onmeasure方法,所以不支持wrap_content(效果为match_parent)
所以需要使用imageview做分割线,支持wrap_content

设置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 1
        versionName "1.0"
    }

获取当前应用和程序的版本号

    public static String getAppVersionName(Context context) {
        String versionName = "";
        int versioncode=0;
        try {
            // ---get the package info---
            PackageManager pm = context.getPackageManager();
            PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
            versionName = pi.versionName;
            versioncode = pi.versionCode;
            if (versionName == null || versionName.length() <= 0) {
                return "";
            }
        } catch (Exception e) {
        }
        return versionName;
    }
    private String getVersionName() throws Exception
    {
        // 获取packagemanager的实例
        PackageManager packageManager = getPackageManager();
        // getPackageName()是你当前类的包名,0代表是获取版本信息
        PackageInfo packInfo = packageManager.getPackageInfo(getPackageName(),0);
        String version = packInfo.versionName;
        return version;
    }

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;
        } else
            i = 0;
        md5Memcpy(buffer, inbuf, index, i, inputLen - i);

    }
    private void md5Final() {
        byte[] bits = new byte[8];
        int index, padLen;
        Encode(bits, count, 8);
        index = (int) (count[0] >>> 3) & 0x3f;
        padLen = (index < 56) ? (56 - index) : (120 - index);
        md5Update(PADDING, padLen);
        md5Update(bits, 8);
        Encode(digest, state, 16);
    }
    private void md5Memcpy(byte[] output, byte[] input, int outpos, int inpos, int len) {
        int i;

        for (i = 0; i < len; i++)
            output[outpos + i] = input[inpos + i];
    }
    private void md5Transform(byte block[]) {
        long a = state[0], b = state[1], c = state[2], d = state[3];
        long[] x = new long[16];
        Decode(x, block, 64);
        a = FF(a, b, c, d, x[0], S11, 0xd76aa478L); /* 1 */
        d = FF(d, a, b, c, x[1], S12, 0xe8c7b756L); /* 2 */
        c = FF(c, d, a, b, x[2], S13, 0x242070dbL); /* 3 */
        b = FF(b, c, d, a, x[3], S14, 0xc1bdceeeL); /* 4 */
        a = FF(a, b, c, d, x[4], S11, 0xf57c0fafL); /* 5 */
        d = FF(d, a, b, c, x[5], S12, 0x4787c62aL); /* 6 */
        c = FF(c, d, a, b, x[6], S13, 0xa8304613L); /* 7 */
        b = FF(b, c, d, a, x[7], S14, 0xfd469501L); /* 8 */
        a = FF(a, b, c, d, x[8], S11, 0x698098d8L); /* 9 */
        d = FF(d, a, b, c, x[9], S12, 0x8b44f7afL); /* 10 */
        c = FF(c, d, a, b, x[10], S13, 0xffff5bb1L); /* 11 */
        b = FF(b, c, d, a, x[11], S14, 0x895cd7beL); /* 12 */
        a = FF(a, b, c, d, x[12], S11, 0x6b901122L); /* 13 */
        d = FF(d, a, b, c, x[13], S12, 0xfd987193L); /* 14 */
        c = FF(c, d, a, b, x[14], S13, 0xa679438eL); /* 15 */
        b = FF(b, c, d, a, x[15], S14, 0x49b40821L); /* 16 */

        a = GG(a, b, c, d, x[1], S21, 0xf61e2562L); /* 17 */
        d = GG(d, a, b, c, x[6], S22, 0xc040b340L); /* 18 */
        c = GG(c, d, a, b, x[11], S23, 0x265e5a51L); /* 19 */
        b = GG(b, c, d, a, x[0], S24, 0xe9b6c7aaL); /* 20 */
        a = GG(a, b, c, d, x[5], S21, 0xd62f105dL); /* 21 */
        d = GG(d, a, b, c, x[10], S22, 0x2441453L); /* 22 */
        c = GG(c, d, a, b, x[15], S23, 0xd8a1e681L); /* 23 */
        b = GG(b, c, d, a, x[4], S24, 0xe7d3fbc8L); /* 24 */
        a = GG(a, b, c, d, x[9], S21, 0x21e1cde6L); /* 25 */
        d = GG(d, a, b, c, x[14], S22, 0xc33707d6L); /* 26 */
        c = GG(c, d, a, b, x[3], S23, 0xf4d50d87L); /* 27 */
        b = GG(b, c, d, a, x[8], S24, 0x455a14edL); /* 28 */
        a = GG(a, b, c, d, x[13], S21, 0xa9e3e905L); /* 29 */
        d = GG(d, a, b, c, x[2], S22, 0xfcefa3f8L); /* 30 */
        c = GG(c, d, a, b, x[7], S23, 0x676f02d9L); /* 31 */
        b = GG(b, c, d, a, x[12], S24, 0x8d2a4c8aL); /* 32 */

        a = HH(a, b, c, d, x[5], S31, 0xfffa3942L); /* 33 */
        d = HH(d, a, b, c, x[8], S32, 0x8771f681L); /* 34 */
        c = HH(c, d, a, b, x[11], S33, 0x6d9d6122L); /* 35 */
        b = HH(b, c, d, a, x[14], S34, 0xfde5380cL); /* 36 */
        a = HH(a, b, c, d, x[1], S31, 0xa4beea44L); /* 37 */
        d = HH(d, a, b, c, x[4], S32, 0x4bdecfa9L); /* 38 */
        c = HH(c, d, a, b, x[7], S33, 0xf6bb4b60L); /* 39 */
        b = HH(b, c, d, a, x[10], S34, 0xbebfbc70L); /* 40 */
        a = HH(a, b, c, d, x[13], S31, 0x289b7ec6L); /* 41 */
        d = HH(d, a, b, c, x[0], S32, 0xeaa127faL); /* 42 */
        c = HH(c, d, a, b, x[3], S33, 0xd4ef3085L); /* 43 */
        b = HH(b, c, d, a, x[6], S34, 0x4881d05L); /* 44 */
        a = HH(a, b, c, d, x[9], S31, 0xd9d4d039L); /* 45 */
        d = HH(d, a, b, c, x[12], S32, 0xe6db99e5L); /* 46 */
        c = HH(c, d, a, b, x[15], S33, 0x1fa27cf8L); /* 47 */
        b = HH(b, c, d, a, x[2], S34, 0xc4ac5665L); /* 48 */

        a = II(a, b, c, d, x[0], S41, 0xf4292244L); /* 49 */
        d = II(d, a, b, c, x[7], S42, 0x432aff97L); /* 50 */
        c = II(c, d, a, b, x[14], S43, 0xab9423a7L); /* 51 */
        b = II(b, c, d, a, x[5], S44, 0xfc93a039L); /* 52 */
        a = II(a, b, c, d, x[12], S41, 0x655b59c3L); /* 53 */
        d = II(d, a, b, c, x[3], S42, 0x8f0ccc92L); /* 54 */
        c = II(c, d, a, b, x[10], S43, 0xffeff47dL); /* 55 */
        b = II(b, c, d, a, x[1], S44, 0x85845dd1L); /* 56 */
        a = II(a, b, c, d, x[8], S41, 0x6fa87e4fL); /* 57 */
        d = II(d, a, b, c, x[15], S42, 0xfe2ce6e0L); /* 58 */
        c = II(c, d, a, b, x[6], S43, 0xa3014314L); /* 59 */
        b = II(b, c, d, a, x[13], S44, 0x4e0811a1L); /* 60 */
        a = II(a, b, c, d, x[4], S41, 0xf7537e82L); /* 61 */
        d = II(d, a, b, c, x[11], S42, 0xbd3af235L); /* 62 */
        c = II(c, d, a, b, x[2], S43, 0x2ad7d2bbL); /* 63 */
        b = II(b, c, d, a, x[9], S44, 0xeb86d391L); /* 64 */

        state[0] += a;
        state[1] += b;
        state[2] += c;
        state[3] += d;

    }
    private void Encode(byte[] output, long[] input, int len) {
        int i, j;

        for (i = 0, j = 0; j < len; i++, j += 4) {
            output[j] = (byte) (input[i] & 0xffL);
            output[j + 1] = (byte) ((input[i] >>> 8) & 0xffL);
            output[j + 2] = (byte) ((input[i] >>> 16) & 0xffL);
            output[j + 3] = (byte) ((input[i] >>> 24) & 0xffL);
        }
    }
    private void Decode(long[] output, byte[] input, int len) {
        int i, j;

        for (i = 0, j = 0; j < len; i++, j += 4)
            output[i] = b2iu(input[j]) | (b2iu(input[j + 1]) << 8) | (b2iu(input[j + 2]) << 16)
                    | (b2iu(input[j + 3]) << 24);

        return;
    }
    public static long b2iu(byte b) {
        return b < 0 ? b & 0x7F + 128 : b;
    }
    public static String byteHEX(byte ib) {
        char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
        char[] ob = new char[2];
        ob[0] = Digit[(ib >>> 4) & 0X0F];
        ob[1] = Digit[ib & 0X0F];
        String s = new String(ob);
        return s;
    }
    public static void main(String argv[]) {
        System.out.println(MD5.getMD5("123".getBytes()));
    }
}

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

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

第一次加载Fragment时,给EditText赋值后,remove后,重新加载这个Fragment,并且给EditText重新赋值,可是页面上显示EditText仍然为原来的值。

原因:
当fragment已存在时,重新加载会执行onViewStateRestored把原有的控件数据重新赋值回来。onViewStateRestored在onActivityCreated(Bundle)后面执行,所以onViewCreated里面的mobileEt被覆盖掉了。

解决办法,重写onViewStateRestored
 @Override
    public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
        super.onViewStateRestored(savedInstanceState);
        mobileEt.setText(mobile);
    }

Recyclerview上拉加载更多

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

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

如果item的根布局使用了linearlayout,framelayout会出现宽高都为wrap_content的问题

解决:
在adapter中,
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        //第一 二种inflate方式都不行
        View.inflate(parent.getContext(),R.layout.item_msg_chat,null);
        LayoutInflater.from(parent.getContext()).inflate(R.layout.item_msg_chat,null);
        //这种才不会有这种奇怪的情况
        View view = LayoutInflater.from(parent.getContext())
        .inflate(R.layout.item_msg_chat, parent, false);
        return new ViewHolder(view);
    }

TextView自动换行

        <TextView
            android: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 {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
            Toast.makeText(context, "network changed:"+getConnectedType(context), Toast.LENGTH_LONG).show();
        }
    }
    public int getConnectedType(Context context) {
        if (context != null) {
            ConnectivityManager mConnectivityManager = (ConnectivityManager) context
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
            if (mNetworkInfo != null && mNetworkInfo.isAvailable()) {
                return mNetworkInfo.getType();
            }
        }
        return -1;
    }
}

注册:
       //通过广播监控网络状态
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        registerReceiver(new NetWorkStatusReceiver(),intentFilter);

判断当前网络是否可用

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    public boolean isNetworkConnected(Context context) {
        if (context != null) {
            ConnectivityManager mConnectivityManager = (ConnectivityManager) context
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
            if (mNetworkInfo != null) {
                return mNetworkInfo.isAvailable();
            }
        }
        return false;
    }

    //获取网络类型
    public static final int TYPE_NOT_NET=0;

    public static final int TYPE_WIFI        = 1;
    public static final int TYPE_MOBILE_MMS  = 2;
    public static final int TYPE_MOBILE_SUPL = 3;
    public static final int TYPE_MOBILE_DUN  = 4;
    public static final int TYPE_MOBILE_HIPRI = 5;
    public static final int TYPE_WIMAX       = 6;
    public static final int TYPE_BLUETOOTH   = 7;
    public static final int TYPE_DUMMY       = 8;
    public static final int TYPE_ETHERNET    = 9;
    public static final int TYPE_MOBILE_FOTA = 10;
    public static final int TYPE_MOBILE_IMS  = 11;
    public static final int TYPE_MOBILE_CBS  = 12;
    public static final int TYPE_WIFI_P2P    = 13;
    public static final int TYPE_MOBILE_IA = 14;
    public static final int TYPE_MOBILE_EMERGENCY = 15;
    public static final int TYPE_PROXY = 16;
    public static final int TYPE_VPN = 17;
    public int getConnectedType(Context context) {
        if (context != null) {
            ConnectivityManager mConnectivityManager = (ConnectivityManager) context
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
            if (mNetworkInfo != null && mNetworkInfo.isAvailable()) {
                return mNetworkInfo.getType();
            }
        }
        return -1;
    }

Handler清空所有任务

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

使用FragmentTabHost时获取fragment实例

1.
String tabs[] = new String[]{"家长留言", "上课打卡", "主页", "校园信箱"};
2.
        for (int i = 0; i < tabs.length; i++) {
        //在这里传入的值就是tag
            TabHost.TabSpec tabSpec = mTabHost.newTabSpec(tabs[i]);
            tabSpec.setIndicator(getView(i));
            mTabHost.addTab(tabSpec, classes[i], null);
        }
3.可以通过fragmentmanager的findFragmentByTag(String tag)来获取fragmeng实例
ItemFragment2 fragment = (ItemFragment2) mManager.findFragmentByTag("上课打卡");       

自定义相机的时候

/mnt/sdcard/Pictures/20170921-10:46:08.png: open failed: EINVAL (Invalid argument)

保存失败,发现保存时图片中不能带有:号

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

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.pop_setting);
            //解决alertdialog不能弹出输入法的问题
            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
                    |WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
        }
    }

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-->Export3.在弹出的导出窗口中,打开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项目运行乱码

一般是由于编码格式错误引起的
可以在modulegradle中修改
android {
    compileSdkVersion 26
    buildToolsVersion "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-28
    Date date = new Date();//当前时间
    String dateStr = format.format(date);

测试数据

08-28 03:00:04.087 11104-11104/com.ct.teacheripa V/meee: school_id=41010004
08-28 03:00:04.087 11104-11104/com.ct.teacheripa V/meee: type=1
08-28 03:00:04.087 11104-11104/com.ct.teacheripa V/meee: date=2017-08-28
08-28 03:00:04.087 11104-11104/com.ct.teacheripa V/meee: login_name=410100045001
08-28 03:00:04.087 11104-11104/com.ct.teacheripa V/meee: class_id=41010004G55C0
08-28 03:00:04.087 11104-11104/com.ct.teacheripa V/meee: school_id=41010004

Android Studio混淆

生成签名的apk
build >generate Signed Apk>输入两次密码
基本混淆模版
在module的build.gradle
android {
    ......
    buildTypes {
        release {
            //开启混淆
            minifyEnabled true
            // Zipalign优化
            zipAlignEnabled true
            // 移除无用的resource文件
            shrinkResources true
            //第一个是系统默认的基本混淆,第二个是自定义的混淆PLUS
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }
}

proguard-rules.pro模版

#############################################
#
# 对于一些基本指令的添加
#
#############################################
# 代码混淆压缩比,在0~7之间,默认为5,一般不做修改
-optimizationpasses 5

# 混合时不使用大小写混合,混合后的类名为小写
-dontusemixedcaseclassnames

# 指定不去忽略非公共库的类
-dontskipnonpubliclibraryclasses

# 这句话能够使我们的项目混淆后产生映射文件
# 包含有类名->混淆后类名的映射关系
-verbose

# 指定不去忽略非公共库的类成员
-dontskipnonpubliclibraryclassmembers

# 不做预校验,preverify是proguard的四个步骤之一,Android不需要preverify,去掉这一步能够加快混淆速度。
-dontpreverify

# 保留Annotation不混淆
-keepattributes *Annotation*,InnerClasses

# 避免混淆泛型
-keepattributes Signature

# 抛出异常时保留代码行号
-keepattributes SourceFile,LineNumberTable

# 指定混淆是采用的算法,后面的参数是一个过滤器
# 这个过滤器是谷歌推荐的算法,一般不做更改
-optimizations !code/simplification/cast,!field/*,!class/merging/*


#############################################
#
# Android开发中一些需要保留的公共部分
#
#############################################

# 保留我们使用的四大组件,自定义的Application等等这些类不被混淆
# 因为这些子类都有可能被外部调用
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Appliction
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.view.View
-keep public class com.android.vending.licensing.ILicensingService


# 保留support下的所有类及其内部类
-keep class android.support.** {*;}

# 保留继承的
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**

# 保留R下面的资源
-keep class **.R$* {*;}

# 保留本地native方法不被混淆
-keepclasseswithmembernames class * {
    native <methods>;
}

# 保留在Activity中的方法参数是view的方法,
# 这样以来我们在layout中写的onClick就不会被影响
-keepclassmembers class * extends android.app.Activity{
    public void *(android.view.View);
}

# 保留枚举类不被混淆
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

# 保留我们自定义控件(继承自View)不被混淆
-keep public class * extends android.view.View{
    *** get*();
    void set*(***);
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

# 保留Parcelable序列化类不被混淆
-keep class * implements android.os.Parcelable {
    public static final android.os.Parcelable$Creator *;
}

# 保留Serializable序列化的类不被混淆
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    !static !transient <fields>;
    !private <fields>;
    !private <methods>;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

# 对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆
-keepclassmembers class * {
    void *(**On*Event);
    void *(**On*Listener);
}

# webView处理,项目中没有使用到webView忽略即可
-keepclassmembers class fqcn.of.javascript.interface.for.webview {
    public *;
}
-keepclassmembers class * extends android.webkit.webViewClient {
    public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
    public boolean *(android.webkit.WebView, java.lang.String);
}
-keepclassmembers class * extends android.webkit.webViewClient {
    public void *(android.webkit.webView, jav.lang.String);
}

对于有些旧版本的项目并没有proguard-rules.pro,stackoverflow中有解答

Looks like your project is missing proguard files. You can add it yourself: put the proguard-rules.txt file into the app directory. It's already added to your build.gradle file so no further actions required.

shareimprove this answer
answered Jul 29 '15 at 9:52

aga
17.3k75079
3       
Android Studio older version do not include proguard-rules.pro automatically, so manually adding it works...Thank you !! – Kushal Jul 29 '15 at 13:14 

Android Studio关联SVN

只有安装了command linesvn可以关联as(默认不安装)
在安装svn配置选项中选择command line>>will be installedas中的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>>ipconfig

3.在模拟器中网络 >>详细设置中设置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单例模式,让请求带上cookies
    static final AsyncHttpClient client = new AsyncHttpClient();
    public static void loadSchoolBuspisition(String url,
            String value, final OnLodaSchoolbusPisition loadListener){
    //设置post的请求参数       
    RequestParams params = new RequestParams();
    params.put("key", value);
    //使用client的post()发起请求,并使用接口进行回调
    client.post(url, params, new AsyncHttpResponseHandler() {
            @Override
            public void onFailure(int arg0, Header[] arg1, byte[] arg2,
                    Throwable arg3) {
            //arg0是响应码
            }

            @Override
            public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {
            //arg2是数据流
            String result = new String(arg2);
            //通过接口进行回调
            loadListener.OnFinish(list, status);
            }
        });
    }       
}

ZoomImageView(手势缩放图片框架)

github:
https://github.com/sephiroth74/ImageViewZoom

1.导包
gradle:
compile 'it.sephiroth.android.library.imagezoom:imagezoom:+'

2.使用方法
setImageBitmap( final Bitmap bitmap, Matrix matrix );
setImageBitmap( final Bitmap bitmap, Matrix matrix, float minZoom, float maxZoom );

如果你想加载一张新的bmp(the same from another ImageView ),你可以使用
Matrix matrix = mImageView1.getDisplayMatrix();
mImageView2.setImageBitmap( bitmap, matrix);

Matrix(将图片放大到占满屏幕)

        //获取屏幕的宽高
        DisplayMetrics dm = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(dm);
        widths = dm.widthPixels;
        heights = dm.heightPixels;

        //获取图片的参数
        bitmap = BitmapFactory.decodeByteArray(datas, 0, datas.length, options);
        Bitmap BitmapOrg = bitmap;
        int width = BitmapOrg.getWidth();
        int height = BitmapOrg.getHeight();
        //目标宽高为屏幕的宽高
        int newWidth = widths;
        int newHeight = heights;
        //当前宽高和屏幕宽高的比例
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        //取较小值
        float bls = scaleWidth < scaleHeight ? scaleWidth : scaleHeight;
        Matrix matrix = new Matrix();
        matrix.postScale(bls, bls);
        bitmap = Bitmap.createBitmap(BitmapOrg, 0, 0, width, height, matrix, true);

图片的边界压缩

        private Bitmap yasuo(String filePath) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        // 获取这个图片的宽和高
        BitmapFactory.decodeFile(filePath, options); //此时返回bm为空
        //设置缩放比
        options.inSampleSize = 2;
        //重新读入图片,注意这次要把options.inJustDecodeBounds 设为 false哦
        options.inJustDecodeBounds = false;
        Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);
        return bitmap;
    }

保存图片至本地和本地图库

    //保存图片至本地
    public static void saveImageToGallery(Context context, Bitmap bmp) {
        if (bmp==null){
            Toast.makeText(context,"保存图片失败",Toast.LENGTH_SHORT).show();
            return;
        }
        // 首先保存图片
        File appDir = new File(Environment.getExternalStorageDirectory(), "Boohee");
        if (!appDir.exists()) {
            appDir.mkdir();
        }
        String fileName = System.currentTimeMillis() + ".jpg";
        File file = new File(appDir, fileName);
        try {
            FileOutputStream fos = new FileOutputStream(file);
            bmp.compress(CompressFormat.JPEG, 100, fos);
            fos.flush();
            fos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 其次把文件插入到系统图库
        try {
            MediaStore.Images.Media.insertImage(context.getContentResolver(),
                    file.getAbsolutePath(), fileName, null);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        //解决在部分机器缓存更新不及时问题
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            Intent mediaScanIntent = new Intent(
                    Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
            Uri contentUri = Uri.fromFile(file); //out is your output file
            mediaScanIntent.setData(contentUri);
            context.sendBroadcast(mediaScanIntent);
        } else {
            context.sendBroadcast(new Intent(
                    Intent.ACTION_MEDIA_MOUNTED,
                    Uri.parse("file://" + Environment.getExternalStorageDirectory())));
        }
        Toast.makeText(context, "保存成功", 1).show();
    }

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 framework
    testCompile 'junit:junit:4.12'
    // Optional -- Mockito framework
    testCompile 'org.mockito:mockito-core:1.10.19'

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

然后又显示code-1 error
    //单元测试显示code -1error的解决办法
    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() {
            @Override
            public void run() {

                Looper.prepare();
                //todo
                Looper.loop();

            }
        };
        mPoolThread.start();

从网络下载图片并保存

    public static boolean downloadImgByUrl(String urlStr, File file) {
        FileOutputStream fos = null;
        InputStream is = null;
        try {
            URL url = new URL(urlStr);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();

            is = conn.getInputStream();
            fos = new FileOutputStream(file);
            byte[] buf = new byte[512];
            int len = 0;
            while ((len = is.read(buf)) != -1) {
                fos.write(buf, 0, len);
            }
            fos.flush();
            return true;

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

            try {
                if (fos != null)
                    fos.close();
            } catch (IOException e) {
            }
        }
        return false;
    }

获取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的大小设置为4m
        int maxsize = 4 * 1024 * 1024;
        lruCache = new LruCache<String, Bitmap>(maxsize) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getRowBytes() * value.getHeight();
            }
        };
    }

    /**
     * @param context
     * @param url
     * @return
     */
    public static Bitmap setBitmapFromCache(Context context, String url) {

        if (TextUtils.isEmpty(url)) {
            return null;
        }
        Bitmap bitmap = null;
        //先从内存缓存中查找图片资源
        bitmap = getBitmapFromMemotyCache(url);
        if (bitmap != null) {
            return bitmap;
        }
        //再从应用的缓存目录中查找图片
        bitmap = getBitmapFormFileCache(context, url);
        if (bitmap != null) {
            return bitmap;
        }
        //再从网络上去异步请求
        bitmap = getBitmapAsyncLoad(url, context);
        if (bitmap != null) {
            return bitmap;
        }
        return null;
    }


    //从缓存文件中取数据
    private static Bitmap getBitmapFormFileCache(Context context, String url) {
        Bitmap bitmap = null;
        String fileName = url.substring(url.lastIndexOf("/") + 1);
        //获得应用的缓存目录
        File cacheDir = null;
        try {
            cacheDir = context.getCacheDir();
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (cacheDir != null) {
            File[] files = cacheDir.listFiles();
            for (int i = 0; i < files.length; i++) {
                if (files[i].getName().equals(fileName)) {
                    bitmap = BitmapFactory.decodeFile(files[i].getAbsolutePath());
                    return bitmap;
                }
            }
        }
        return null;
    }

    //从lrucache中取bmp
    private static Bitmap getBitmapFromMemotyCache(String url) {
        Bitmap bitmap = null;
        if (url != null) {
            bitmap = lruCache.get(url);
        }
        return bitmap;
    }
    //从网络中请求数据
    private static Bitmap getBitmapAsyncLoad(String url,
                                             Context context) {
        MyAsyncTask task = new MyAsyncTask(context);
        task.execute(url);
        return null;
    }


    //异步任务
    static class MyAsyncTask extends AsyncTask<String, Void, Bitmap> {
        Context context;

        public MyAsyncTask(Context context) {
            this.context = context;

        }

        @Override
        protected Bitmap doInBackground(String... params) {
            Bitmap bitmap = null;
            String path = params[0];
            try {
                URL url = new URL(path);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setConnectTimeout(5000);
                connection.setRequestMethod("GET");
                connection.setDoInput(true);
                if (connection.getResponseCode() == 200) {
                    InputStream inputStream = connection.getInputStream();
                    //把返回的图片资源做按比例缩放的处理
                    bitmap = CompressBitmap(inputStream);
                    //存入缓存
                    if (bitmap != null) {
                        lruCache.put(path, bitmap);
                        bitmapCacheFile(bitmap, path, context);
                    }
                }
            } catch (Exception e) {
                // TODO: handle exception
            }
            return null;
        }

        @Override
        protected void onPostExecute(Bitmap result) {


            super.onPostExecute(result);
        }
        //保存到本地缓存
        private void bitmapCacheFile(Bitmap bitmap, String path,
                                     Context context2) throws FileNotFoundException {
            File cacheFile = context2.getCacheDir();
            // TODO Auto-generated method stub
            if (!cacheFile.exists()) {
                cacheFile.mkdirs();
            }
            String fileName = path.substring(path.lastIndexOf("/") + 1);
            File file = new File(cacheFile, fileName);
            OutputStream stream = new FileOutputStream(file);
            bitmap.compress(CompressFormat.JPEG, 100, stream);
        }

        //对图片进行压缩
        private Bitmap CompressBitmap(InputStream inputStream) {
            byte[] datas = StreamUtil.getBytesFromStream(inputStream);
            BitmapFactory.Options options = new BitmapFactory.Options();
            //只获取图片的参数
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeByteArray(datas, 0, datas.length, options);
            //边界的宽高
            int outWidth = options.outWidth;
            int outHeight = options.outHeight;
            int targetWidth = 70;
            int targetHeight = 70;
            int wbl = outWidth / targetWidth;
            int hbl = outHeight / targetHeight;
            int bl = wbl > hbl ? wbl : hbl;
            if (bl < 0) {
                bl = 1;
            }
            options.inSampleSize = bl;
            options.inJustDecodeBounds = false;
            Bitmap bitmap = BitmapFactory.decodeByteArray(datas, 0, datas.length, options);
            return bitmap;
        }
    }
}

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;
        } else
            i = 0;
        md5Memcpy(buffer, inbuf, index, i, inputLen - i);
    }

    /*
     * md5Final整理和填写输出结 
     */
    private void md5Final() {
        byte[] bits = new byte[8];
        int index, padLen;

        // /* Save number of bits */
        Encode(bits, count, 8);

        // /* Pad out to 56 mod 64.
        index = (int) (count[0] >>> 3) & 0x3f;
        padLen = (index < 56) ? (56 - index) : (120 - index);
        md5Update(PADDING, padLen);

        // /* Append length (before padding) */
        md5Update(bits, 8);

        // /* Store state in digest */
        Encode(digest, state, 16);

    }

    /*
     * md5Memcpy是个内部使用的byte数组的块拷贝函数,从input的inpos 始把len长度  字节拷贝到output的outpos位置  
     */

    private void md5Memcpy(byte[] output, byte[] input, int outpos, int inpos, int len) {
        int i;

        for (i = 0; i < len; i++)
            output[outpos + i] = input[inpos + i];
    }

    /*
     * md5Transform是MD5核心变换程式,有md5Update调用,block是分块的原始字节
     */
    private void md5Transform(byte block[]) {
        long a = state[0], b = state[1], c = state[2], d = state[3];
        long[] x = new long[16];

        Decode(x, block, 64);

        /* Round 1 */
        a = FF(a, b, c, d, x[0], S11, 0xd76aa478L); /* 1 */
        d = FF(d, a, b, c, x[1], S12, 0xe8c7b756L); /* 2 */
        c = FF(c, d, a, b, x[2], S13, 0x242070dbL); /* 3 */
        b = FF(b, c, d, a, x[3], S14, 0xc1bdceeeL); /* 4 */
        a = FF(a, b, c, d, x[4], S11, 0xf57c0fafL); /* 5 */
        d = FF(d, a, b, c, x[5], S12, 0x4787c62aL); /* 6 */
        c = FF(c, d, a, b, x[6], S13, 0xa8304613L); /* 7 */
        b = FF(b, c, d, a, x[7], S14, 0xfd469501L); /* 8 */
        a = FF(a, b, c, d, x[8], S11, 0x698098d8L); /* 9 */
        d = FF(d, a, b, c, x[9], S12, 0x8b44f7afL); /* 10 */
        c = FF(c, d, a, b, x[10], S13, 0xffff5bb1L); /* 11 */
        b = FF(b, c, d, a, x[11], S14, 0x895cd7beL); /* 12 */
        a = FF(a, b, c, d, x[12], S11, 0x6b901122L); /* 13 */
        d = FF(d, a, b, c, x[13], S12, 0xfd987193L); /* 14 */
        c = FF(c, d, a, b, x[14], S13, 0xa679438eL); /* 15 */
        b = FF(b, c, d, a, x[15], S14, 0x49b40821L); /* 16 */

        /* Round 2 */
        a = GG(a, b, c, d, x[1], S21, 0xf61e2562L); /* 17 */
        d = GG(d, a, b, c, x[6], S22, 0xc040b340L); /* 18 */
        c = GG(c, d, a, b, x[11], S23, 0x265e5a51L); /* 19 */
        b = GG(b, c, d, a, x[0], S24, 0xe9b6c7aaL); /* 20 */
        a = GG(a, b, c, d, x[5], S21, 0xd62f105dL); /* 21 */
        d = GG(d, a, b, c, x[10], S22, 0x2441453L); /* 22 */
        c = GG(c, d, a, b, x[15], S23, 0xd8a1e681L); /* 23 */
        b = GG(b, c, d, a, x[4], S24, 0xe7d3fbc8L); /* 24 */
        a = GG(a, b, c, d, x[9], S21, 0x21e1cde6L); /* 25 */
        d = GG(d, a, b, c, x[14], S22, 0xc33707d6L); /* 26 */
        c = GG(c, d, a, b, x[3], S23, 0xf4d50d87L); /* 27 */
        b = GG(b, c, d, a, x[8], S24, 0x455a14edL); /* 28 */
        a = GG(a, b, c, d, x[13], S21, 0xa9e3e905L); /* 29 */
        d = GG(d, a, b, c, x[2], S22, 0xfcefa3f8L); /* 30 */
        c = GG(c, d, a, b, x[7], S23, 0x676f02d9L); /* 31 */
        b = GG(b, c, d, a, x[12], S24, 0x8d2a4c8aL); /* 32 */

        /* Round 3 */
        a = HH(a, b, c, d, x[5], S31, 0xfffa3942L); /* 33 */
        d = HH(d, a, b, c, x[8], S32, 0x8771f681L); /* 34 */
        c = HH(c, d, a, b, x[11], S33, 0x6d9d6122L); /* 35 */
        b = HH(b, c, d, a, x[14], S34, 0xfde5380cL); /* 36 */
        a = HH(a, b, c, d, x[1], S31, 0xa4beea44L); /* 37 */
        d = HH(d, a, b, c, x[4], S32, 0x4bdecfa9L); /* 38 */
        c = HH(c, d, a, b, x[7], S33, 0xf6bb4b60L); /* 39 */
        b = HH(b, c, d, a, x[10], S34, 0xbebfbc70L); /* 40 */
        a = HH(a, b, c, d, x[13], S31, 0x289b7ec6L); /* 41 */
        d = HH(d, a, b, c, x[0], S32, 0xeaa127faL); /* 42 */
        c = HH(c, d, a, b, x[3], S33, 0xd4ef3085L); /* 43 */
        b = HH(b, c, d, a, x[6], S34, 0x4881d05L); /* 44 */
        a = HH(a, b, c, d, x[9], S31, 0xd9d4d039L); /* 45 */
        d = HH(d, a, b, c, x[12], S32, 0xe6db99e5L); /* 46 */
        c = HH(c, d, a, b, x[15], S33, 0x1fa27cf8L); /* 47 */
        b = HH(b, c, d, a, x[2], S34, 0xc4ac5665L); /* 48 */

        /* Round 4 */
        a = II(a, b, c, d, x[0], S41, 0xf4292244L); /* 49 */
        d = II(d, a, b, c, x[7], S42, 0x432aff97L); /* 50 */
        c = II(c, d, a, b, x[14], S43, 0xab9423a7L); /* 51 */
        b = II(b, c, d, a, x[5], S44, 0xfc93a039L); /* 52 */
        a = II(a, b, c, d, x[12], S41, 0x655b59c3L); /* 53 */
        d = II(d, a, b, c, x[3], S42, 0x8f0ccc92L); /* 54 */
        c = II(c, d, a, b, x[10], S43, 0xffeff47dL); /* 55 */
        b = II(b, c, d, a, x[1], S44, 0x85845dd1L); /* 56 */
        a = II(a, b, c, d, x[8], S41, 0x6fa87e4fL); /* 57 */
        d = II(d, a, b, c, x[15], S42, 0xfe2ce6e0L); /* 58 */
        c = II(c, d, a, b, x[6], S43, 0xa3014314L); /* 59 */
        b = II(b, c, d, a, x[13], S44, 0x4e0811a1L); /* 60 */
        a = II(a, b, c, d, x[4], S41, 0xf7537e82L); /* 61 */
        d = II(d, a, b, c, x[11], S42, 0xbd3af235L); /* 62 */
        c = II(c, d, a, b, x[2], S43, 0x2ad7d2bbL); /* 63 */
        b = II(b, c, d, a, x[9], S44, 0xeb86d391L); /* 64 */

        state[0] += a;
        state[1] += b;
        state[2] += c;
        state[3] += d;

    }

    /*
     * Encode把long数组按顺序拆成byte数组,因为java的long类型 64bit的, 只拆 32bit,以适应原始C实现的用 
     */
    private void Encode(byte[] output, long[] input, int len) {
        int i, j;

        for (i = 0, j = 0; j < len; i++, j += 4) {
            output[j] = (byte) (input[i] & 0xffL);
            output[j + 1] = (byte) ((input[i] >>> 8) & 0xffL);
            output[j + 2] = (byte) ((input[i] >>> 16) & 0xffL);
            output[j + 3] = (byte) ((input[i] >>> 24) & 0xffL);
        }
    }

    /*
     * Decode把byte数组按顺序合成成long数组,因为java的long类型 64bit的,
     * 只合成低32bit,高32bit清零,以适应原始C实现的用 
     */
    private void Decode(long[] output, byte[] input, int len) {
        int i, j;

        for (i = 0, j = 0; j < len; i++, j += 4)
            output[i] = b2iu(input[j]) | (b2iu(input[j + 1]) << 8) | (b2iu(input[j + 2]) << 16)
                    | (b2iu(input[j + 3]) << 24);

        return;
    }

    /*
     * 把byte按照不虑虑正负号的原则的"升位"程式,因为java没有unsigned运算
     */
    public static long b2iu(byte b) {
        return b < 0 ? b & 0x7F + 128 : b;
    }

    //用来把一个byte类型的数转换成十六进制的ASCII表示 
    public static String byteHEX(byte ib) {
        char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
        char[] ob = new char[2];
        ob[0] = Digit[(ib >>> 4) & 0X0F];
        ob[1] = Digit[ib & 0X0F];
        String s = new String(ob);
        return s;
    }

    public static void main(String argv[]) {
        System.out.println(MD5.getMD5("123".getBytes()));
    }
}

StreamUtils

public class StreamUtil {
    //把inputStrem转换为String
    public static byte[] getBytesFromStream(InputStream is){
        byte[] datas=null;
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = is.read(buffer)) != -1) {
                outputStream.write(buffer,0,len);
            }
            datas=outputStream.toByteArray();
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(is!=null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return datas;
    }
}

自定义控件:可缩放的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()
                {
                    @Override
                    public boolean onDoubleTap(MotionEvent e)
                    {
                        //如果是自动缩放,则终止该方法
                        if (isAutoScale == true)
                            return true;

                        float x = e.getX();
                        float y = e.getY();

                        //获取缩放比例,对此进行判断,并设置到自动缩放的任务
                        if (getScale() < SCALE_MID)
                        {
                            ZoomImageView.this.postDelayed(

                                    new AutoScaleRunnable(SCALE_MID, x, y), 16);
                            isAutoScale = true;
                        } else if (getScale() >= SCALE_MID
                                && getScale() < SCALE_MAX)
                        {
                            ZoomImageView.this.postDelayed(
                                    new AutoScaleRunnable(SCALE_MAX, x, y), 16);
                            isAutoScale = true;
                        } else
                        {
                            ZoomImageView.this.postDelayed(
                                    new AutoScaleRunnable(initScale, x, y), 16);
                            isAutoScale = true;
                        }
                        return true;
                    }
                });
        //缩放手势的监听
        mScaleGestureDetector = new ScaleGestureDetector(context, this);
        this.setOnTouchListener(this);
    }

    /**
     * 自动缩放的任务
     * 
     * @author zhy
     * 
     */
    private class AutoScaleRunnable implements Runnable
    {
        static final float BIGGER = 1.07f;
        static final float SMALLER = 0.93f;
        private float mTargetScale;
        private float tmpScale;

        /**
         * 缩放的中心
         */
        private float x;
        private float y;

        /**
         * 传入目标缩放值,
         * 根据目标值与当前值,判断应该放大还是缩小
         * @param targetScale
         */
        public AutoScaleRunnable(float targetScale, float x, float y)
        {
            this.mTargetScale = targetScale;
            this.x = x;
            this.y = y;
            if (getScale() < mTargetScale)
            {
                tmpScale = BIGGER;
            } else
            {
                tmpScale = SMALLER;
            }
        }

        @Override
        public void run()
        {
            // 进行缩放
            mScaleMatrix.postScale(tmpScale, tmpScale, x, y);
            checkBorderAndCenterWhenScale();
            setImageMatrix(mScaleMatrix);

            final float currentScale = getScale();
            // 如果值在合法范围内,继续缩放
            if (((tmpScale > 1f) && (currentScale < mTargetScale))
                    || ((tmpScale < 1f) && (mTargetScale < currentScale)))
            {
                ZoomImageView.this.postDelayed(this, 16);
            } else
            // 设置为目标的缩放比例
            {
                final float deltaScale = mTargetScale / currentScale;
                mScaleMatrix.postScale(deltaScale, deltaScale, x, y);
                checkBorderAndCenterWhenScale();
                setImageMatrix(mScaleMatrix);
                isAutoScale = false;
            }
        }
    }

    //缩放手势的操作
    @SuppressLint("NewApi")
    @Override
    public boolean onScale(ScaleGestureDetector detector)
    {
        float scale = getScale();
        float scaleFactor = detector.getScaleFactor();

        if (getDrawable() == null)
            return true;
        /**
         * 缩放的范围控制
         */
        if ((scale < SCALE_MAX && scaleFactor > 1.0f)
                || (scale > initScale && scaleFactor < 1.0f))
        {
            /**
             * 最大值最小值判断
             */
            if (scaleFactor * scale < initScale)
            {
                scaleFactor = initScale / scale;
            }
            if (scaleFactor * scale > SCALE_MAX)
            {
                scaleFactor = SCALE_MAX / scale;
            }
            /**
             * 设置缩放比例
             */
            mScaleMatrix.postScale(scaleFactor, scaleFactor,
                    detector.getFocusX(), detector.getFocusY());
            checkBorderAndCenterWhenScale();
            setImageMatrix(mScaleMatrix);
        }
        return true;
    }

    /**
     * 在缩放时,进行图片显示范围的控制
     */
    private void checkBorderAndCenterWhenScale()
    {

        RectF rect = getMatrixRectF();
        float deltaX = 0;
        float deltaY = 0;

        int width = getWidth();
        int height = getHeight();

        // 如果宽或高大于屏幕,则控制范围
        if (rect.width() >= width)
        {
            if (rect.left > 0)
            {
                deltaX = -rect.left;
            }
            if (rect.right < width)
            {
                deltaX = width - rect.right;
            }
        }
        if (rect.height() >= height)
        {
            if (rect.top > 0)
            {
                deltaY = -rect.top;
            }
            if (rect.bottom < height)
            {
                deltaY = height - rect.bottom;
            }
        }
        // 如果宽或高小于屏幕,则让其居中
        if (rect.width() < width)
        {
            deltaX = width * 0.5f - rect.right + 0.5f * rect.width();
        }
        if (rect.height() < height)
        {
            deltaY = height * 0.5f - rect.bottom + 0.5f * rect.height();
        }
        mScaleMatrix.postTranslate(deltaX, deltaY);

    }

    /**
     * 根据当前图片的Matrix获得图片的范围
     * 
     * @return
     */
    private RectF getMatrixRectF()
    {
        Matrix matrix = mScaleMatrix;
        RectF rect = new RectF();
        Drawable d = getDrawable();
        if (null != d)
        {
            rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
            matrix.mapRect(rect);
        }
        return rect;
    }

    @Override
    public boolean onScaleBegin(ScaleGestureDetector detector)
    {
        return true;
    }

    @Override
    public void onScaleEnd(ScaleGestureDetector detector)
    {
    }

    //触摸事件的监听
    @Override
    public boolean onTouch(View v, MotionEvent event)
    {

        if (mGestureDetector.onTouchEvent(event))
            return true;
        mScaleGestureDetector.onTouchEvent(event);

        float x = 0, y = 0;
        // 拿到触摸点的个数
        final int pointerCount = event.getPointerCount();
        // 得到多个触摸点的x与y均值
        for (int i = 0; i < pointerCount; i++)
        {
            x += event.getX(i);
            y += event.getY(i);
        }
        x = x / pointerCount;
        y = y / pointerCount;

        /**
         * 每当触摸点发生变化时,重置mLasX , mLastY
         */
        if (pointerCount != lastPointerCount)
        {
            isCanDrag = false;
            mLastX = x;
            mLastY = y;
        }
        //保存最后一次的触摸点个数
        lastPointerCount = pointerCount;
        RectF rectF = getMatrixRectF();

        //解决触摸时间的冲突
        switch (event.getAction())
        {
            //对比图片的matrix和屏幕的宽高 >>确定事件是否拦截
        case MotionEvent.ACTION_DOWN:
            //当图片的宽度大于屏幕的空间的宽度的时候
            if (rectF.width() > getWidth() || rectF.height() > getHeight())
            {
                getParent().requestDisallowInterceptTouchEvent(true);
            }
            break;
        case MotionEvent.ACTION_MOVE:
            if (rectF.width() > getWidth() || rectF.height() > getHeight())
            {
                getParent().requestDisallowInterceptTouchEvent(true);
            }
            float dx = x - mLastX;
            float dy = y - mLastY;

            if (!isCanDrag)
            {
                isCanDrag = isCanDrag(dx, dy);
            }
            if (isCanDrag)
            {

                if (getDrawable() != null)
                {
                    isCheckLeftAndRight = isCheckTopAndBottom = true;
                    // 如果宽度小于屏幕宽度,则禁止左右移动
                    if (rectF.width() < getWidth())
                    {
                        dx = 0;
                        isCheckLeftAndRight = false;
                    }
                    // 如果高度小雨屏幕高度,则禁止上下移动
                    if (rectF.height() < getHeight())
                    {
                        dy = 0;
                        isCheckTopAndBottom = false;
                    }
                    mScaleMatrix.postTranslate(dx, dy);
                    checkMatrixBounds();
                    setImageMatrix(mScaleMatrix);
                }
            }
            mLastX = x;
            mLastY = y;
            break;

        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            lastPointerCount = 0;
            break;
        }

        return true;
    }

    /**
     * 获得当前的缩放比例
     * 
     * @return
     */
    public final float getScale()
    {
        mScaleMatrix.getValues(matrixValues);
        return matrixValues[Matrix.MSCALE_X];
    }

    @Override
    protected void onAttachedToWindow()
    {
        super.onAttachedToWindow();
        getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    @SuppressWarnings("deprecation")
    @Override
    protected void onDetachedFromWindow()
    {
        super.onDetachedFromWindow();
        getViewTreeObserver().removeGlobalOnLayoutListener(this);
    }

    @Override
    public void onGlobalLayout()
    {
        if (once)
        {
            Drawable d = getDrawable();
            if (d == null)
                return;
            Log.e(TAG, d.getIntrinsicWidth() + " , " + d.getIntrinsicHeight());
            int width = getWidth();
            int height = getHeight();
            // 拿到图片的宽和高
            int dw = d.getIntrinsicWidth();
            int dh = d.getIntrinsicHeight();
            float scale = 1.0f;
            // 如果图片的宽或者高大于屏幕,则缩放至屏幕的宽或者高
            if (dw > width && dh <= height)
            {
                scale = width * 1.0f / dw;
            }
            if (dh > height && dw <= width)
            {
                scale = height * 1.0f / dh;
            }
            // 如果宽和高都大于屏幕,则让其按按比例适应屏幕大小
            if (dw > width && dh > height)
            {
                scale = Math.min(width * 1.0f / dw, height * 1.0f / dh);
            }
            initScale = scale;

            Log.e(TAG, "initScale = " + initScale);
            mScaleMatrix.postTranslate((width - dw) / 2, (height - dh) / 2);
            mScaleMatrix.postScale(scale, scale, getWidth() / 2,
                    getHeight() / 2);
            // 图片移动至屏幕中心
            setImageMatrix(mScaleMatrix);
            once = false;
        }

    }

    /**
     * 移动时,进行边界判断,主要判断宽或高大于屏幕的
     */
    private void checkMatrixBounds()
    {
        RectF rect = getMatrixRectF();

        float deltaX = 0, deltaY = 0;
        final float viewWidth = getWidth();
        final float viewHeight = getHeight();
        // 判断移动或缩放后,图片显示是否超出屏幕边界
        if (rect.top > 0 && isCheckTopAndBottom)
        {
            deltaY = -rect.top;
        }
        if (rect.bottom < viewHeight && isCheckTopAndBottom)
        {
            deltaY = viewHeight - rect.bottom;
        }
        if (rect.left > 0 && isCheckLeftAndRight)
        {
            deltaX = -rect.left;
        }
        if (rect.right < viewWidth && isCheckLeftAndRight)
        {
            deltaX = viewWidth - rect.right;
        }
        mScaleMatrix.postTranslate(deltaX, deltaY);
    }

    /**
     * 是否是推动行为
     * 
     * @param dx
     * @param dy
     * @return
     */
    private boolean isCanDrag(float dx, float dy)
    {
        return Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop;
    }
}

事件由子控件响应

getParent().requestDisallowInterceptTouchEvent(true);

删除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.在modulegradle
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.在布局中引用样式
<Tv
    Style="@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()中屏蔽下拉效果
    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        banStatusBar();
    }
    //取消下拉的屏蔽
    private void unBanStatusBar() {
        Object service = getSystemService("statusbar");
        try {
            Class<?> statusBarManager = Class.forName
                    ("android.app.StatusBarManager");
            Method expand = statusBarManager.getMethod("disable", int.class);
            expand.invoke(service, DISABLE_NONE);
        } catch (Exception e) {
        }
    }

    //屏蔽下拉
    private void banStatusBar() {
        int currentApiVersion = android.os.Build.VERSION.SDK_INT;
        if (currentApiVersion <= 16) {
            setStatusBarDisable(DISABLE_EXPAND_LOW);
        } else {
            setStatusBarDisable(DISABLE_EXPAND);
        }
    }
    private void setStatusBarDisable(int disable_status) {
        Object service = getSystemService("statusbar");
        try {
            Class<?> statusBarManager = Class.forName
                    ("android.app.StatusBarManager");
            Method expand = statusBarManager.getMethod("disable", int.class);
            expand.invoke(service, disable_status);
        } catch (Exception e) {
            unBanStatusBar();
            e.printStackTrace();
        }
    }

判断当前线程是不是主线程

public boolean isMainThread() {
    return Looper.getMainLooper() == Looper.myLooper();
}
public boolean isMainThread() {
    return Looper.getMainLooper().getThread().getId() == Thread.currentThread().getId();
}

Okhttp的execute()enqueue()

execute是执行的意思,execute()是立即执行,同步执行
enqueue是加入队列的意思,enqueue()是将任务加入线程池的队列中,异步执行
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值