Android知识点[持续更新]

快捷键

ctrl+shift+enter 自动补全
ctrl+alt+space 自动补全选中项
shift+enter 转到下一行

startActivityForResult()

((MainActivity) mContext).startActivityForResult(intent, 100);``requestCode 必须大于0 才能在onActivityResult 中监听到

double 和 float 比较大小 问题

如果两个数值相同,但是类型不同,也会判为不同(精度问题) 记住java一定要用double,就算数值不大也要用double。 float放在内存中其实是当作double来处理的 short,char,boolean,byte在内存中都是以int形式来处理的 当然long类型例外,虽然long类型也会增加资源的开销,但是毕竟能完成int完成不了的功能

自定义layout与第三方layout

自定义layout与第三方layout有时会出现重名,导致错误发生

android 9.0 网络网络请求库不能使用http 且不能使用apache

android webview 监听webload finish事件

webview_basewebview.setWebViewClient(new WebViewClient() {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        return false;
    }

    @Override
    public void onPageFinished(WebView view, String url) {
        loadingDialog.dismiss();
    }
});

webview 加载本地文件 提高加载速度

由于JS文件过大,加载太慢,所以将JS文件放到本地加载,以提高加载速度 主要是用到了 WebViewClient 的shouldInterceptRequest()方法 本地JS文件,放在assets目录下

mWebView.setWebViewClient(new WebViewClient() {
            @Override
            public WebResourceResponse shouldInterceptRequest(WebView webView, String url ) {
                Uri uri = Uri.parse(url);
                String fileName = uri.getLastPathSegment();
                if (SPE_BUNDLE_JS.equals(fileName)) {
                    try {
                        Map<String, String> map = new HashMap<>();
                        map.put("Access-Control-Allow-Origin", "*");
                        map.put("Access-Control-Allow-Headers", "Content-Type");
                        LogUtils.i("Cordova", "加载本地JS:" + fileName);
                        WebResourceResponse resourceResponse = new WebResourceResponse("application/javascript", "UTF-8", 200, "", map, mActivity.getAssets().open(SPE_BUNDLE_JS));
                        return resourceResponse;
                    } catch (Exception e) {
                        e.printStackTrace();
                        return null;//异常情况,直接访问网络资源
                    }
                } else {
                    LogUtils.i(TAG, "加载服务端JS:" + fileName);
                    return super.shouldInterceptRequest(webView, url);
                }
            }
          ....
}

多线程-AsyncTask 异步任务

syncTask,总结起来就是: 3个泛型,4个步骤。

3个泛型

AsyncTask <Params, Progress, Result>

  • Params: 这个泛型指定的是我们传递给异步任务执行时的参数的类型
  • Progress: 这个泛型指定的是我们的异步任务在执行的时候将执行的进度返回给UI线程的参数的类型
  • Result: 这个泛型指定的异步任务执行完后返回给UI线程的结果的类型
  • 在定义一个类继承AsyncTask类的时候,必须要指定好这三个泛型的类型,如果都不指定的话,则都将其写成VoidAsyncTask <Void, Void, Void>

4个步骤

  • onPreExecute(): 这个方法是在执行异步任务之前的时候执行,并且是在UI Thread当中执行的,通常我们在这个方法里做一些UI控件的初始化的操作,例如弹出要给ProgressDialog
  • doInBackground(Params... params): 在onPreExecute()方法执行完之后,会马上执行这个方法,这个方法就是来处理异步任务的方法,Android操作系统会在后台的线程池当中开启一个worker thread来执行我们的这个方法,所以这个方法是在worker thread当中执行的,这个方法执行完之后就可以将我们的执行结果发送给我们的最后一个 onPostExecute 方法,在这个方法里,我们可以从网络当中获取数据等一些耗时的操作
  • onProgressUpdate(Progess... values): 这个方法也是在UI Thread当中执行的,我们在异步任务执行的时候,有时候需要将执行的进度返回给我们的UI界面,例如下载一张网络图片,我们需要时刻显示其下载的进度,就可以使用这个方法来更新我们的进度。这个方法在调用之前,我们需要在 doInBackground 方法中调用一个 publishProgress(Progress) 的方法来将我们的进度时时刻刻传递给 onProgressUpdate 方法来更新
  • onPostExecute(Result... result): 当我们的异步任务执行完之后,就会将结果返回给这个方法,这个方法也是在UI Thread当中调用的,我们可以将返回的结果显示在UI控件上 使用:
    /**
     * Represents an asynchronous login/registration task used to authenticate
     * the user.
     */
    public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {

        private final String mEmail;
        private final String mPassword;

        UserLoginTask(String email, String password) {
            mEmail = email;
            mPassword = password;
        }

        @Override
        protected void onPreExecute() {
            showProgress(true);
        }

        @Override
        protected Boolean doInBackground(Void... params) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                return false;
            }

            for (String credential : DUMMY_CREDENTIALS) {
                String[] pieces = credential.split(":");
                if (pieces[0].equals(mEmail)) {
                    // Account exists, return true if the password matches.
                    return pieces[1].equals(mPassword);
                }
            }
            return true;
        }

        @Override
        protected void onPostExecute(final Boolean success) {
            mAuthTask = null;
            if (success) {
                finish();
            } else {
                showProgress(false);
                mPasswordView.setError(getString(R.string.error_incorrect_password));
                mPasswordView.requestFocus();
            }
        }

        @Override
        protected void onCancelled() {
            mAuthTask = null;
            showProgress(false);
        }
    }

使用AsyncTask

Handler 使用

Bundle bundleData = Algorithm(location);
  if (bundleData != null) {
    LocationHandler locationHandler = new LocationHandler(MapActivity.this);
    Message locationMsg = locationHandler.obtainMessage();
    bundleData.putParcelable("location", location);
    locationMsg.setData(bundleData);
    locationHandler.sendMessage(locationMsg);
}
    ```

## Handler 弱引用处理内存泄漏
```java
  public static class LocationHandler extends Handler {
    WeakReference<MapActivity> mActivity;
    LocationHandler(MapActivity activity) {
        mActivity = new WeakReference<>(activity);
    }
    @Override
    public void handleMessage(Message msg) {
        MapActivity activity = mActivity.get();
        if (activity != null) {
            // TODO: 2019年4月17日
        }
    }
}

推荐使用AppCompatActivity 以及toolbar替代actionBar

toolbar布局 布局文件夹中添加toolbar.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    style="@style/Album.WrapContent.WidthMatchParent"
    android:theme="@style/AppTheme.AppBarOverlay">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:popupTheme="@style/AppTheme.PopupOverlay" />

</android.support.design.widget.AppBarLayout>

其中pupupTheme

<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" >
    <item name="actionOverflowMenuStyle">@style/OverflowMenuStyle</item>
</style>
<style name="OverflowMenuStyle" parent="Widget.AppCompat.Light.PopupMenu.Overflow">
    <item name="overlapAnchor">false</item>
        <!--把该属性改为false即可使menu位置位于toolbar之下-->
</style>
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
<style name="Toolbar.Popup" parent="ThemeOverlay.AppCompat.Light">
        <item name="actionMenuTextColor">@color/fontDark</item>
        <item name="textAllCaps">false</item>
        <item name="android:fitsSystemWindows">true</item><!--设置沉浸式-->
</style>

在使用的地方 <include layout="@layout/toolbar" />就可以有标题栏了

设置返回按钮并监听返回

 Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true);
}

 @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home://监听返回
                this.finish();
            default:
                return true;
        }
        return super.onOptionsItemSelected(item);
}

toolbar title居中

public class Utils {
    public static void setTitleCenter(Toolbar toolbar) {
        if (toolbar == null) return;
        String title = "title";
        final CharSequence originalTitle = toolbar.getTitle();
        toolbar.setTitle(title);
        for (int i = 0; i < toolbar.getChildCount(); i++) {
            View view = toolbar.getChildAt(i);
            if (view instanceof TextView) {
                TextView textView = (TextView) view;
                if (title.equals(textView.getText())) {
                    textView.setGravity(Gravity.CENTER);
                    Toolbar.LayoutParams params = new Toolbar.LayoutParams(Toolbar.LayoutParams.WRAP_CONTENT, Toolbar.LayoutParams.MATCH_PARENT);
                    params.gravity = Gravity.CENTER;
                    textView.setLayoutParams(params);
                }
            }
            toolbar.setTitle(originalTitle);
        }
    }
}

在初始化时使用Utils.setTitleCenter(toolbar);就可以了

设置右侧菜单

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_map_menu, menu);
    return true;
}

menu布局文件

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <group>
        <item
            android:id="@+id/menu_map_normal"
            android:title="@string/map_menu_normal"
            app:showAsAction="never" />
        <item
            android:id="@+id/menu_map_satellite"
            android:title="@string/map_menu_satellite"
            app:showAsAction="never" />
        <item
            android:id="@+id/menu_map_none"
            android:title="@string/map_menu_none"
            app:showAsAction="never" />
    </group>
</menu>

menu菜单监听 同toolbar返回监听

@Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                this.finish();
            case R.id.menu_map_normal:
                mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL);
                break;
            case R.id.menu_map_satellite:
                mBaiduMap.setMapType(BaiduMap.MAP_TYPE_SATELLITE);
                break;
            case R.id.menu_map_none:
                mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NONE);
                break;
            default:
                return true;
        }
        return super.onOptionsItemSelected(item);
}

获取assets资源

assets文件夹目录与java目录时同级

/**
     * 获取Assets 文件内容
     * @param fileName 文件名
     * @param context context
     * @return String
     */
    public static String getJson(String fileName, Context context) {
        //将json数据变成字符串
        StringBuilder stringBuilder = new StringBuilder();
        try {
            //获取assets资源管理器
            AssetManager assetManager = context.getAssets();
            //通过管理器打开文件并读取
            BufferedReader bf = new BufferedReader(new InputStreamReader(assetManager.open(fileName)));
            String line;
            while ((line = bf.readLine()) != null) {
                stringBuilder.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return stringBuilder.toString();
}

gosn解析json

Gson gson=new Gson();
Bean data=gson.fromJson(string,Bean.class);//Bean时定义的实体类

// 从assets中获取json内容并解析
//json内容为
/*
[{"center":[116.41338310930209,37.60701416950952],"id":"0-0"}] //注:类型为Bean
*/
try {
    JSONArray gridDataList = new JSONArray(Utils.getJson("map_grid_data.json", HomeActivity.this));//获取JSONArray
    Type listType = new TypeToken<List<Bean>>() {
    }.getType();//获取类型
    List<Bean> list = new Gson().fromJson(gridDataList.toString(), listType);
    Log.d("HomeActivity", list.toString());
} catch (JSONException e) {
    e.printStackTrace();
}

String[] 转 List<String>

String[] listItems = new String[]{
        "消息类型对话框(蓝色按钮)",
        "消息类型对话框(红色按钮)"
};
List<String> data = new ArrayList<>();
Collections.addAll(data, listItems);

QMUI 配置

1.theme

2.dialog context

Timer 及 Timer取消

mTimer = new Timer();
mTimerTask = new TimerTask() {
    @Override
    public void run() {
        if (isFinished) return;
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (mTipDialog != null) {
                    mTipDialog.show();
                }
            }
        });
    }
};
mTimer.schedule(mTimerTask, 400);

注意: 当acivity已经finish时,timer还没有执行,此时就不能再显示view了,需要再onDestroy中添加变量,监听是否已经finish

取消timer

if (mTimer != null) {
    mTimer.cancel();
    mTimer.purge();//清理timer
    mTimer = null;
}
if (mTimerTask != null) {
    mTimerTask.cancel();
    mTimerTask = null;
}

drawable资源文件尺寸

L DPI ( Low Density Screen,120 DPI ),其图标大小为 36 x 36 px
M DPI ( Medium Density Screen, 160 DPI ),其图标大小为 48 x 48 px
H DPI ( High Density Screen, 240 DPI ),其图标大小为 72 x 72 px
XH DPI ( Extra-high density screen, 320 DPI ),其图标大小为 96 x 96 px
XXH DPI( xx-high density screen, 480 DPI ),其图标大小为144 x 144 px
XXXH DPI( xxx-high density screen, 640 DPI ),其图标大小为192 x 192 px

assets 权限 android9.0

fragment 使用

menu显示图片和文字

异步任务处理方式:

1.AsyncTask 2.AsyncQueryHandler 3.Thread + Handler (Looper) 4.Timer,TimerTask 5.HandlerThead 6.LoaderCallbacks

如果handler不是在子线程中定义,handler.post()方法实际上还是在主线程中执行 AsyncQueryHandler,HandlerThread则都是另起一个子线程去进行数据处理(对于两者的使用区别,如果我们只需要进行一次异步查询,如加载通话记录,使用AsyncQueryHandler更为方便。如果需要一个工作者线程,则建议使用Handler。ThreadHandlerThread通过其mLooper对象实现了对消息队列处理逻辑的简易封装) AsyncTask则适合在进行后台操作时需要更新UI时的场景 每个Activity和fragment都对应一个LoaderManager

gradlle 的buildTypes内部配置

示例:

buildTypes {
    debug {
        // 服务器配置
        buildConfigField "String", "SERVERHEAD","\"http://110.11.11.00/miaomiao/\""
        //是否混淆 默认为false
        minifyEnabled false
        //是否对齐app所有资源
        zipAlignEnabled true
        //移除无用的resource文件
        shrinkResources false
        proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
        signingConfig signingConfigs.debug
        }
    release {
        // 正式服务器
        buildConfigField "String", "SERVERHEAD","\"http://miaomiao.com/miaomiao/\""
        //混淆
        minifyEnabled true
        zipAlignEnabled true//内存对齐
        // 移除无用的resource文件
        shrinkResources true
        proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
        //签名
        signingConfig signingConfigs.release
    }
}

可以直接在android{}内配置签名信息,代码如下:

signingConfigs {
    debug {
        //miaomiao_keystore.jks文件最好放在项目app目录下
        storeFile file("miaomiao_keystore.jks")
        storePassword "123456"
        keyAlias "miaomiao"
        keyPassword "123456"
        }
    release {
        //miaomiao_keystore.jks文件最好放在项目app目录下
        storeFile file("miaomiao_keystore.jks")
        storePassword "123456"
        keyAlias "miaomiao"
        keyPassword "123456"
        }
    }

buildConfigField 字段参数配置,android的gradle会根据buildTypes的配置自动生成BuildConfig.java文件,直接在项目接口配置的java文件内通过类名调用获取,可以避免每次调试与正式打包时容易忘记切换服务器的问题,省去出错麻烦 使用buildConfigField

//服务器头字段
public static final String SERVER_HEADER = BuildConfig.SERVERHEAD;

以下一般为默认属性即可:

debuggable: debug模式默认为true, release模式默认是false
jniDebuggable: debug模式与release模式默认都是false
renderscriptDebuggable: debug模式与release模式默认都是false

StrictMode(严格模式)的使用

StrictMode严格模式,主要用来检测程序中违例情况的开发者工具。最常用的场景就是检测主线程中本地磁盘、网络读写等耗时的操作以及Activity泄露等,但该模式不建议在Release版本开启,此外该模式无法监控JNI中的磁盘IO和网络请求且其违例情况仅供参考,需结合实际开发需求予以解决。 封装

public class DebugUtil {  
    public static void startStrictModeVmPolicy(){  
        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()  
        .detectActivityLeaks()/*检测Activity内存泄露*/  
        .detectLeakedClosableObjects()/*检测未关闭的Closable对象*/  
        .detectLeakedSqlLiteObjects() /*检测Sqlite对象是否关闭*/     
        /*也可以采用detectAll()来检测所有想检测的东西*/  
        .penaltyLog().build());  
    }  
    public static void startStrictModeThreadPolicy(){  
        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()  
        .detectDiskReads()/*磁盘读取操作检测*/  
        .detectDiskWrites()/*检测磁盘写入操作*/  
        .detectNetwork() /*检测网络操作*/     
        /*也可以采用detectAll()来检测所有想检测的东西*/  
        .penaltyLog().build());  
}  
}

需要查看TAG为StrictMode的日志即可,如:logcat -c;logcat -s StrictMode 或者adb logcat | grep StrictMode

  • 获取当前context的方法
getApplicationContext()

注解 butterknife

AutoCompleteTextView MultiAutoCompleteTextView

Notification

定位错误方法

在项目root路径,命令行cmd输入:

gradlew processDebugResources --debug
//打印到txt文件
gradlew processDebugResources --debug > ./debug.txt
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,492评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,048评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,927评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,293评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,309评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,024评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,638评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,546评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,073评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,188评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,321评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,998评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,678评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,186评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,303评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,663评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,330评论 2 358

推荐阅读更多精彩内容

  • 一 Activity 1 Activity 生命周期 1.1 Activity 的四种状态 running 当前...
    _执_念__阅读 10,397评论 0 91
  • 1、Android 线程间通信有哪几种方式(重要) 共享内存(变量);文件,数据库、Handler;Java 里的...
    李成新阅读 381评论 0 0
  • 0.Android手机操作系统的四层架构? Applications , Application Framewor...
    lucas777阅读 7,849评论 0 16
  • 1.Android系统的架构 1.Android系统架构之应用程序 Android会同一系列核心应用程序包一起发布...
    QM阅读 2,037评论 0 50
  • Android面试题包括Android基础,还有一些源码级别的、原理这些等。所以想去大公司面试,一定要多看看源码和...
    勤息嘻嘻嘻阅读 713评论 0 1