碎雨(五)

okhttp调https

        参考

        如果后台使用的https证书为认证过的,那前端只需要将http://换成https://即可。否则,前端需要信任后台提示的证书才能继续访问。代码如下:

public void setCertificates(InputStream... certificates) {
        try {
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null);
            int index = 0;
            for (InputStream certificate : certificates) {
                String certificateAlias = Integer.toString(index++);
                keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));
                try {
                    if (certificate != null)
                        certificate.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            SSLContext sslContext = SSLContext.getInstance("TLS");
            TrustManagerFactory trustManagerFactory =
                    TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            sslContext.init
                    (
                            null,
                            trustManagerFactory.getTrustManagers(),
                            new SecureRandom()
                    );
            mOkHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
        其中参数为后台提供的cer文件的流。再使用时,使用mOkHttpClient去进行网络访问即可。

子线程更新UI

        都知道在子线程中不能更新UI。但在子线程中同样也不能更新跟UI绑定的数据源,如对ListView的数据源为一个List集合,如果在子线程中更新了该集合,可能会报如下错误:

win10下adb无法连接设备

        在win10下,adb能成功打开,只是adb devices显示的是空的。原文解决办法。打开设备管理器,连接上之后的列表如下:


而无法连接时,没有第一个Android Device选项。解决办法为:
        1,右键,以管理员身份运行sdk manager,并在sdk manager中下载google Usb Driver
        2,打开设备管理器,里有一个其他设备,点开,选择其中一个右键->更新驱动程序软件(其他几个也类似的操作,如果有的话)。
        3,在弹出的框中选择第二项:浏览计算机查找驱动程序软件。
        4,再选择"从计算机的设备驱动列表中选取"
        5,选择"从磁盘安装"
        6,将\sdk\extras\google\usb_driver的全路径指定成为文件来源。然后一路确定。
        7,一般来说,一个手机安装成功后,换另一个手机时仍旧需要重新安装(至少我试四个手机就安装了四会),但一个手机安装过一次后就不需要再次安装了。

内存溢出与内存泄漏

        内存泄漏:该回收的内存未回收。比如使用Cursor之后未关闭,使用完Bitmap后未recycler()。
        内存溢出:程序申请的内存超过系统能给予的上限。比如显示图片未压缩时。造成内存溢出的原因有很多,比如:1,对图片的显示未进行压缩,也未进行缓存等。2,内存泄漏,大量的内存泄漏会造成内存空间的无意义浪费,最终会导致内存不足。3,在会重复执行的操作中new出大量的对象。比如系统不建议我们在onDraw()方法中new出Paint等对象,因为在执行动画时onDraw()会不断的调用。每调用一次就new出一些对象,而gc又来不及回收,最终导致内存不足,造成内存溢出。

复制粘贴

        调用系统的ClipboardManager进行操作。也可以监听系统剪贴板内容的变化。如下:
    ClipboardManager.OnPrimaryClipChangedListener mPrimaryChangeListener
            = new ClipboardManager.OnPrimaryClipChangedListener() {
        public void onPrimaryClipChanged() {
            updateClipData(true);
        }
    };

        ClipboardManager mClipboard = (ClipboardManager)getSystemService(CLIPBOARD_SERVICE);
        mClipboard.addPrimaryClipChangedListener(mPrimaryChangeListener);
它常用方法如下:
        setPrimaryClip(ClipData):向剪贴板中添加数据。
        getPrimaryClip():从剪贴板中获取数据,返回一个ClipData对象。

        hasPrimaryClip():剪贴板中是否有数据。
        getDescription():获取剪贴板中内容的描述。它包括两部分:第一部分为内容的MIME类型,第二部分为生成ClipData时传递的Label。
        removePrimaryClipChangedListener()与addPrimaryClipChangedListener():移除和添加对剪贴板内容的监听。一般在Activity#onDestory中移除监听。

ClipData

        ClipboardManager#setPrimaryClip()的参数为一个ClipData。它代表着存储于剪贴板中的数据。任何向剪贴板中添加的数据必须先封装到一个ClipData中。每一次粘贴时,都粘贴的是上一个ClipData中的内容。ClipData中的数据是存储于其内部的若干个Item中的,这些Item是用一个ArrayList集合进行存储的(叫mItems)。
静态方法:
        newPlainText(String,String):粘贴的内容为一个纯文本。对应的MIME为text/plain。其中第一个参数就是getDescription()返回的label。
        newHtmlText(String,String,String):粘贴的内容为一个HTML代码,第二个参数为不支持html显示时显示的内容,第三个参数为真正的html代码。如粘贴的内容为<b>test</b>,那么显示时会显示成加粗的test。对应的MIME为text/html。
        newIntent(String,Intent):粘贴的内容为一个Intent对象,对应的MIME为text/vnd.android.intent。
        newRawUri(String,Uri):粘贴的内容为一个Uri对象。对应的MIME为text/uri-list。
非静态方法
        addItem():向ClipData中添加一个Item数据,使用该方法可以将分布于不同地方的内容一起复制到剪贴板中。上面的静态方法中,首先会将参数封装到一个Item中,然后再调用addItem(),将封装得到的Item添加到mItems中。因此,可以直接调用addItem()方法向剪贴板中添加数据。如:
                ClipData data = ClipData.newRawUri("LABEL",Uri.parse("http://www.baidu.com/"));
                ClipData.Item item = new ClipData.Item("html","<b>html</b>");
                data.addItem(item);
                manager.setPrimaryClip(data);
        此时粘贴的内容将公是http://www.baidu.com/[换行]html(文字加粗)。这是因为该data中有两个item,每一个item存储了一条数据。
        getItemCount():获取该ClipData对象中的Item的数量。
        getItemAt():获取位于某个index位置的item对象。

Item

        ClipData的内部类,它才是直接存储粘贴内容的。在复制时,会先将内容封装到一个Item中,然后将Item添加到ClipData对象中,再将该对象通过ClipboardManager#setPrimaryClip设置到系统中,这样别的应用就可以使用自己的复制内容了。
        由于一个Item是直接存储复制内容的,因此可以通过它的方法获取到复制的内容。如下:
        getText():获取item中存储的文字。
        getHtmlText():获取该item中存储的html代码。
        getUri():获取该item中存储的Uri。
        getIntent():获取该item中存储的intent。
        这些方法都是由创建Item时传入的参数形式是对应的。

示例

                ClipData data = ClipData.newRawUri("LABEL",Uri.parse("http://www.baidu.com/"));
                ClipData.Item item = new ClipData.Item("html","<b>html</b>");
                data.addItem(item);
                ClipData.Item item1 = new ClipData.Item("text");
                data.addItem(item1);
                ClipData.Item item2 = new ClipData.Item(new Intent(Intent.ACTION_VIEW,Uri.parse("http://www.google.com/")));
                data.addItem(item2);//为一次复制添加多个item。
                manager.setPrimaryClip(data);//设置到系统中
                ClipData clip = manager.getPrimaryClip();
                for(int x = 0;x<clip.getItemCount();x++){
                    ClipData.Item at = clip.getItemAt(x);
                    switch (x){
                        case 0:
                            Log.e(TAG,"0="+at.getUri().toString());//第一个是通过newRawUri创建的item,所以获取时只能通过getUri。如果使用getText()等方法,将会返回null
                            break;
                        case 1:
                            Log.e(TAG,"1="+at.getHtmlText()+",c = "+at.coerceToHtmlText(MainActivity.this));
                            break;
                        case 2:
                            Log.e(TAG,"2="+at.getText());
                            break;
                        case 3:
                            Log.e(TAG,"3="+at.getIntent().toUri(0));
                            break;
                    }
                }

multidex

        每一个dex文件最多只能有65536个方法,多了就是出异常。解决办法将一个dex文件分解成多个dex文件。不幸的是,低版本的android系统中不支持多个dex文件(而5.0以上是自动支持的),但官方又提供有相应的support包。

        第一步:修改module级的gradle文件,如下:

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.0"

    defaultConfig {
        ...
        minSdkVersion 14
        targetSdkVersion 21
        ...

        // Enabling multidex support.
        multiDexEnabled true
    }
    ...
}

dependencies {
  compile 'com.android.support:multidex:1.0.0'
}
        第二步:修改Application。如果没有自定义的Application,那只需要修改清单文件如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.multidex.myapplication">
    <application
        ...
        android:name="android.support.multidex.MultiDexApplication">
        ...
    </application>
</manifest>
        其中name属性指定引用support包中的MultiDexApplication。
        如果自身已经定义过了Application,那么重写attachBaseContext()方法将调用MultiDex.install(this)

日间模式与夜间模式

        方法一:设置不同的theme。参考

        方法二:使用v7中自带的功能。方法如下:

        1,Activity要继承AppCompatActivity;2,Activity的theme为Theme.AppCompat.DayNight或其子类;3,通过如下示例的代码进行日夜切换:

    public void setModeNightNo(View view) {
        getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_NO);//日间模式
        recreate();
    }

    public void setModeNightYes(View view) {
        getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES);//夜间模式
        recreate();
    }

    public void setModeNightAuto(View view) {
        getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_AUTO);//自动
        recreate();
    }

        这种方式也可用在dialog上,只不过dialog的创建得使用v7包中的AppCompatDialog。如下:

        AppCompatDialog dialog = new AppCompatDialog(this, R.style.Theme_AppCompat_DayNight_Dialog);
        dialog.getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_AUTO);
        dialog.setTitle(R.string.dialog_title);
        dialog.setContentView(R.layout.dialog_content);
        dialog.show();

        虽然这种切换方式比较简单,但它不如上面的一个灵活:上面一个可以设置成想要设置的颜色,并且可以实现多个主题。而下面的处理全部是系统自动完成,只有两种主题。

几个线程的比较

        android提供了几个关于线程操作的类:AsyncTask,HandlerThread,IntentService,再加上Java自向的Executor。一共四个。

        1,AsyncTask默认是串行的,因此,它适合执行起来比较迅速的任务。但它的操作简单。

        2,IntentService,启动一个Service,并在线程中执行每一个Intent。因此,它适合执行长期任务,并且其优先级比普通的后台线程要高。

        3,HandlerThread,比较灵活。

        4,Executor:线程池,需要多个线程并发执行时用。

        大部分情况下都可用AsyncTask,但它本身就有一些限制,如:一个对象只能执行一次,内容采用的是线程池技术,所以有可能不同的AsyncTask执行在不同的线程中。如果说需要为某些连接执行的任务提供一个单独的线程,使用HandlerThread比AsyncTask合适。

        无论是采用哪一种线程,在Activity结束时都需要保证线程能正常结束,因为线程持有一个Activity的引用,如果它不结束将会导致Activity无法被回收,从而内存泄漏。

        另外,在使用线程时,需要考虑自己线程的优先级。应根据业务进行调整。

mac下插入环境变量

        1,打开terminal(终端),输入vim ~/.bash_profile(该文件用来配置个人的环境变量)。

        2,按i键,即在vim中进入插入模式,可以进行修改。

        3,按esc键,退出个性,并输入:wq后保存退出


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值