Android中遇到的好的博文

(一)Andoird Studio 错误: 非法字符: '\ufeff'

参照连接这里解决。缘由是as没法识别BOM的问题。人生中第一次遇到这个问题是大学时写PHP,那时候就紧紧的记住个了。时隔这么多年,在另外一款编辑器另外一种语言中又遇到了,缘分啊!html

(二)关于AlertDialog

这里如出一辙的内容) 有关于AlertDialog的基本使用,基本能够参考到了。不过更好的是如何与AlertDialog交互的问题,有一篇文章写得特别好,可是找不到了。java

在onClick(DialogInterface,int,int which)中,能够经过DialogInterface的getId来区分弹出的AlertDialog,按键则经过which了。这种状况适合于将全部的AlterDialog的onClick回调所有绑定到自身的状况了。android

(三)ListView

这里ListView使用的文章,而这个是关于android.R.layout里面定义的与listview有关的那部分xml说明,值得参考。这个详细的介绍了adapter状况,值得回味一下git

简书中的这篇文章简单却颇有效的介绍了BaseAdapter的用法,比其余的更加有效,看完以后就基本了解了其原理及应用github


(四)自带图标

这里是有关android自带的系统图标,能够经过android.R.drawable/访问,至少用做临时的place holder也能够嘛!sql

(五)Android问题与之thisActivity.this的区别

这里有关Activity.this与this区别。写过js因此的对于闭包有些惧怕,但在这里因而乎仍是一目了然。数据库

fab_save.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mOptStatus = OperationStatus.Other;
                if (mArea.getCount() == 0) {
                    Toast.makeText(MainApplication.getContext(), "请先圈定范围", Toast.LENGTH_SHORT).show();
                } else {
                    View vv = LayoutInflater.from(MainApplication.getContext()).inflate(R.layout.save_line_dialog, null);
                    save_name_et = (EditText) vv.findViewById(R.id.save_line_et);
                    save_line_ad = new AlertDialog.Builder(getActivity())
                            .setTitle("输入名称")
                            .setView(vv)
                            .setPositiveButton("保存", iActivity.this)
                            .setNegativeButton("取消", null).create();
                    save_line_ad.show();
                }
            }
        });

(六)ListView的onItemLongClick不被触发

这里表述了这二者(LongClick和Click)的过程。默认状况下as自动生成的代码模板,LongClick是返回false。若是想本身触发,则须要手动改为true.编程

@Override
    public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
        mItem_index=position;
        del_prj_ad.show();
        return true;
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        mItem_index=position;
        open_prj_ad.show();
    }

/*json

*    好吧,后来发现即便长按,也没有弹出Dialog,非常奇怪啊,segmentfault

*    仔细查看后发现是没有注册onItemLongClick,很差意思,可是应该仍是有关系的,

*    要否则总会瞎onItemClick的。

*/

这里还有一个对Button或者ImageButton长按的说明,道理类似。

 

(七)org.json.JSONArray没有add方法

这个问题只有去访问该项目的github,不过看完以后仍是会惊叹,果真是没有。它自己不打算考虑像ArrayList那样能够add到任意的index(虽然它内部的实现仍是使用ArrayList),而经过put(Object o)方法就是将o放到内部List的尾部(直接List.add(o)),而put(index,o)是更改内部index位置的对象,不是想象的add(index,o)的实现。好了,想insert的想法是不能有的。

能够考虑新建对象,可是,开销太大了点,不值得。

(八)Java的泛型

使用泛型,确实是使用java的ArrayList<E>,可是知道这个(或者类似概念)要算是学习C++时涉及到的模板(template)。segmentF的讲解和排版都不错,是个入门的教程。提到的《java编程思想》也确实值得学习。这个的例子仍是蛮多。

讲真,能想到用泛型的,估计都是手懒到必定程度了吧。我怎么想到用泛型了呢?不一样的类型,却面对着相同的操做。即便是实现了相同的接口,却也没法将类型传递进去,承受着这种手忙脚乱的感受,忽然念叨了Python的好。

public JSONArray returnResult(ArrayList<IInterface> ii)
{
    JSONArray a=new JSONArray();
    for(IInterface i:ii)
    {
        a.put(i.toJson());//看着也能够呀,忘记了不行的写法了
    }
    return a;
}

(九)Activity与Fragment的生存周期

这个事情很烦躁啊,也多是没认真研究的缘故。这里讲了动态与静态(即xml文件)处理frgment的问题,谁知道是否是坑呢。而这个研究的很细致了,将每个过程(onCreate,onStart等等)说的很清楚,排版不错呦。

(十)Handler与Looper的机制

这里算是简介,而这里讲的很是透彻,固然在我还没弄清除以前还不能写太多评论。个人代码有些卡顿了。不知为什么。慢慢的调试中。

int vol_id=0x01;
    int salt_id=0x02;
    int space_id=0x03;
    Handler mHandler=new Handler(new Handler.Callback(){
        @Override
        public boolean handleMessage(Message msg) {
            Log.i("E","xxxxxx"+ msg.what);
            if(msg.what==vol_id)
                if(vol_tv!=null)
                {
                    vol_tv.setText(vol_tv_text);
                }
            else if(msg.what==salt_id)
                if(salt_tv!=null)
                {
                    salt_tv.setText(salt_tv_text);
                }
            else if(msg.what==space_id)
                if(space_tv!=null)
                {
                    space_tv.setText(space_tv_text);
                }
            return false;
        }
    });

(十一)TextView中getBackground返回为null

网络上能搜索到的关于设置和获取TextView的代码不少,除了有关于考虑android版本状况的,其余的几乎是一致的。

然而本身的代码确实是总返回null,调试中能够看到mColor为空。在代码中,本身的空间是从xml布局中直接获取的,虽然在xml的父container中设置了backgroud,可是经过findViewById得到的仍是努力了。最后不得不先尝试,即在findViewById以后手动调用setBackgroundColor,这样再次获取时就成功了。

Stack overflow中的这篇问题中的答案解析比较全面,但仍是没说个人这种状况。

 

(十二)关于使用Sqlite做为本地存储的通用开头

自我感受,这种方式的初始化应该会用得更多,因此记录下来,直接copy就能够了。其中包括了数据库路径优先外置存储器选择,适当改改也能够进行单利化。

public class PathDatabase extends SQLiteOpenHelper {
    public static int version=1;
    public static String db_name="name.db";
    String table_name="table";
    SQLiteDatabase mSQLiteDatabase;
    private PathDatabase(Context c,String full_db_name){
        super(c,full_db_name,null,PathDatabase.version);
    }
    public static PathDatabase getInstance(Context c){
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)&&Environment.isExternalStorageEmulated())
        {
            return new PathDatabase(c,Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+db_name);
        }else {
            return new PathDatabase(c,db_name);
        }
    }

关于sqlite得到id的问题,insert方法确实能够得到插入数据的rowid,文档上就这么写的。

public long insert (String table, String nullColumnHack, ContentValues values)

Added in API level 1

Convenience method for inserting a row into the database.

Parameters

table the table to insert the row into
nullColumnHack optional; may be null. SQL doesn't allow inserting a completely empty row without naming at least one column name. If your provided values is empty, no column names are known and an empty row can't be inserted. If not set to null, the nullColumnHack parameter provides the name of nullable column name to explicitly insert a NULL into in the case where your values is empty.
values this map contains the initial column values for the row. The keys should be the column names and the values the column values

Returns

  • the row ID of the newly inserted row, or -1 if an error occurred

可是呢,又有提出,使用rowid做为主键是很不安全的,由于rowid会更改,作法就是

If you don’t want to read the whole post then just do this: Everytime you create a table with sqlite make sure to have an INTEGER PRIMARY KEY AUTOINCREMENT column (the rowid column will be an alias to this one).

因此我考虑就这么定义吧,希望insert的时候返回的是这货。

(十三)onBackPressed

对于现现在的系统,Activity中有处理按返回键的事件,public void onBackPressed(),固然自动生成的会有super方法,也就会触发退出事件,通常会直接改掉。这个是具体的介绍,而这个介绍了双击退出键退出程序的写法,无非就是用时间差,简单而高效有用。我还想到用2秒自毁线程,而后在主线程中判断是否运行,实际上会挺犯不上的。

Simple is better than complex
public class Common {
    public static long last_time_click=-1;
    public static int backclick_internal=2;
}

@Override
    public void onBackPressed() {
        if((System.currentTimeMillis()-Common.last_time_click)<Common.backclick_internal){
            finish();
            System.exit(0);
        }else{
            Common.last_time_click=System.currentTimeMillis();
        }
    }

(十四)动态更改View的宽度等

动态更改是经过LinearLayout.LayoutParams来更改,调用View.setLayoutParams,好比这里说的清楚。可是遇到两个事情:java.lang.ClassCastException和宽度问题。

CastException问题是在给View的时候,可是这里的param应该是其父容器的类型,即在转换的时候(View.getLayoutParam获取的是ViewGroup.LayoutParams对象,须要强制转换)给出正确的类型。这里说明了一下,确实很准确。

RelativeLayout.LayoutParams mLayoutParams;
 public void onClick(View v) {
            mLayoutParams=(RelativeLayout.LayoutParams)mView.getLayoutParams();
            if(mImageButton1.isSelected()){
                mImageButton1.setSelected(false);
                mLayoutParams.width= Util.dip2px(Util.change_map_type_short_width);
            }else{
                mImageButton1.setSelected(true);
                mLayoutParams.width=Util.dip2px(Util.change_map_type_long_width);
            }
            mView.setLayoutParams(mLayoutParams);
}

宽度是由于在代码中赋值给width是像素值,而多数状况下是dip的数值,这须要进行转换计算。这里给了代码,可是感受通用性不强,因而本身改造了Application类,见(十五)。经过静态方法,将计算的scale值放在第一次运行时计算。

public class Util {
    public static int px2dip(float pxValue) {
        return (int) (pxValue / MyApplication.scale + 0.5f);
    }
    public static int dip2px(float dpValue) {

        return (int) (dpValue * MyApplication.scale+0.5f);
    }
}

 

(十五)全局获取Context对象

这种方式是最为方便的,虽然没有顾忌太多的。这里是博客,下面是根据本身须要改造后配合上面计算像素与dip转换。

public class MyApplication extends Application {
    private  static Context context;

    @Override
    public void onCreate() {
        super.onCreate();
        context=getApplicationContext();
        scale=context.getResources().getDisplayMetrics().density;
    }

    public static Context getContext() {
        return context;
    }
    public static float scale ;
}

(十六)振动器

经过服务获取便可,惟一的就是几个参数:一个是使用一个毫秒数来震动多久,另外一个是两个参数,前一个是long数组,两两结合表示停顿时间,震动时间,第二个参数表示循环起始下标,若是使用-1则表示震动一次。具体的参看这里或者这里。代码抄至后者。

vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
vibrator.vibrate(2000);//震动指定时间 ,数据类型long,单位为毫秒,一毫秒为1/1000秒
vibrator.vibrate(new long[]{100,10,100,1000}, -1);//按照指定的模式去震动。
vibrator.cancel();//取消震动,当即中止震动。震动为一直震动的话,若是不取消震动,就算退出,也会一直震动

(十七)int类型的List

这个很基础,只惋惜没注意过,或者没有学过。应为List以及ArrayList中只能存放继承至Object的对象,对于值类型不支持,可是可使用其封装为Object的Integer以及相似的对象,好比这里说明的意思。

 

(十八)准确获取储存卡的路径

本来我使用的方法是下面。

public static Database getInstance(Context c){
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)&&Environment.isExternalStorageEmulated())
        {
            return new PathDatabase(c,Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+db_name);
        }else {
            return new Database(c,db_name);
        }
    }

可是发现,储存卡与sdcard的关系不必定,有多是sdcard1才是储存卡因此须要一个准确的获取方法。

这里讲的很是全面。以前一直使用其余写法。原理之后能够详看(主要是Java的反射机制),下面代码就抄过来了。这个写的也不错,可是内容也差很少,作补充。

import java.lang.reflect.Method;  
    import android.os.storage.StorageManager;  
      
        // 获取主存储卡路径  
        public String getPrimaryStoragePath() {  
            try {  
                StorageManager sm = (StorageManager) getSystemService(STORAGE_SERVICE);  
                Method getVolumePathsMethod = StorageManager.class.getMethod("getVolumePaths", null);  
                String[] paths = (String[]) getVolumePathsMethod.invoke(sm, null);  
                // first element in paths[] is primary storage path  
                return paths[0];  
            } catch (Exception e) {  
                Log.e(TAG, "getPrimaryStoragePath() failed", e);  
            }  
            return null;  
        }  
          
        // 获取次存储卡路径,通常就是外置 TF 卡了. 不过也有多是 USB OTG 设备...  
        // 其实只要判断第二章卡在挂载状态,就能够用了.  
        public String getSecondaryStoragePath() {  
            try {  
                StorageManager sm = (StorageManager) getSystemService(STORAGE_SERVICE);  
                Method getVolumePathsMethod = StorageManager.class.getMethod("getVolumePaths", null);  
                String[] paths = (String[]) getVolumePathsMethod.invoke(sm, null);  
                // second element in paths[] is secondary storage path  
                return paths.length <= 1 ? null : paths[1];  
            } catch (Exception e) {  
                Log.e(TAG, "getSecondaryStoragePath() failed", e);  
            }  
            return null;  
        }  
          
        // 获取存储卡的挂载状态. path 参数传入上两个方法获得的路径  
        public String getStorageState(String path) {  
            try {  
                StorageManager sm = (StorageManager) getSystemService(STORAGE_SERVICE);  
                Method getVolumeStateMethod = StorageManager.class.getMethod("getVolumeState", new Class[] {String.class});  
                String state = (String) getVolumeStateMethod.invoke(sm, path);  
                return state;  
            } catch (Exception e) {  
                Log.e(TAG, "getStorageState() failed", e);  
            }  
            return null;  
        }

 

 

博客

Hongyang

guolin

相关文章
相关标签/搜索