Android小提示一-阿里云开发者社区

开发者社区> zerosboy> 正文

Android小提示一

简介: Android开发一些小提示
+关注继续查看
Other

启动页黑屏处理:
https://www.jianshu.com/p/0026a01c6811
https://www.cnblogs.com/liqw/p/4263418.html

//在根布局节点设置clipChildren=false,这个属性默认为true.意思是是否限制子视图在其范围内。
//其次就是要用layout_gravity来控制超出的部分显示位置。
android:clipChildren="false"

如:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:clipChildren="false">
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="40dip"
        android:background="#B0C4DE"
        android:orientation="horizontal"
        android:layout_alignParentBottom="true">
 
        <ImageView
            android:layout_width="0dip"
            android:layout_height="fill_parent"
            android:layout_weight="1.0"
            android:scaleType="fitCenter"
            android:src="@mipmap/ic_launcher" />
 
        <ImageView
            android:layout_width="0dip"
            android:layout_height="fill_parent"
            android:layout_weight="1.0"
            android:scaleType="fitCenter"
            android:src="@mipmap/ic_launcher" />
 
        <ImageView
            android:layout_width="0dip"
            android:layout_height="75dip"
            android:layout_gravity="bottom"
            android:layout_weight="1.0"
            android:scaleType="fitCenter"
            android:src="@mipmap/ic_launcher" />
 
        <ImageView
            android:layout_width="0dip"
            android:layout_height="fill_parent"
            android:layout_weight="1.0"
            android:scaleType="fitCenter"
            android:src="@mipmap/ic_launcher" />
 
        <ImageView
            android:layout_width="0dip"
            android:layout_height="fill_parent"
            android:layout_weight="1.0"
            android:scaleType="fitCenter"
            android:src="@mipmap/ic_launcher" />
    </LinearLayout>

【比重】: https://www.cnblogs.com/net168/p/4227144.html

【1.StringBuffer与StringBuilder】

StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。
StringBuilder 的方法不是线程安全的(不能同步访问)。
由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。

//1.去除字符串换行符
s=s.replaceAll("\r|\n","");

//方法2
public static String replaceBlank(String str) {
    String dest = "";
    if (str!=null) {
    Pattern p = Pattern.compile("\\s*|\t|\r|\n");
    Matcher m = p.matcher(str);
    dest = m.replaceAll("");
    }
    return dest;
}
【2.网络DefaultHttpClient】

从Android API Level 23(Android 6.0)开始,不能再在Android中使用DefaultHttpClient,强制使用HttpURLConnection。

【3.URL】

一般情况下,URL的长度不能超过2048个字符,即2KB,超过此限制的话服务器可能就不识别。
URL的最大长度就是2048个字符,如果我们发送的数据很大,超过了2KB怎么办?我们可以将很大的数据放到请求体中,GET请求不支持请求体,只有POST请求才能设置请求体。
https://blog.csdn.net/iispring/article/details/51474529

【4.Intent】

Intent传递数据大小的限制大概在1M左右,超过这个限制就会静默崩溃。

【5.报complie 等错误,及ARouter问题】

一般是xml错误,或者在类继承时导入错误的包
因为Kotlin在编译时不检查导入的包的错误

在Dagger中CashLoan中全部写在一个ActivityComponent中,是因为只有一个Module,如果是多模块的Module则最好用多个ActivityComponent

v4 v7重复依赖问题深究
compile('com.facebook.fresco:fresco:0.10.0') {
       exclude module: 'support-v4'
}
//如果是源码形式引入的开源库:
compile (project(':thirdpart:RecyclerViewAdapterLibrary')){ 
     exclude group: 'com.android.support' 
}

【ARouter::Compiler >>> No module name, for more information, look at gradle log.】
由于ARouter版本原因错误

// 替换成最新版本, 需要注意的是api
// 要与compiler匹配使用,均使用最新版可以保证兼容
compile 'com.alibaba:arouter-api:x.x.x'
annotationProcessor 'com.alibaba:arouter-compiler:x.x.x'
annotationProcessor "com.alibaba:arouter-compiler:1.1.4"
api "com.alibaba:arouter-api:1.3.1"


ARouter.getInstance()
                .build(RouterPath.UserCenter.PATH_LOGIN)
                .withFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
                .withFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
                .navigation()

[https://www.cnblogs.com/baiqiantao/p/10125084.html]()

【6.引入个推/极光等第三方库,报合并清单错误】

1.在清单Application节点下:tools:replace="label,icon,theme" (可以不要)

  1. manifestPlaceholders = [

        GETUI_APP_ID : "APP_ID",
        GETUI_APP_KEY : "APP_KEY",
        GETUI_APP_SECRET : "APP_SECRET"

    ]

所以:引用某个库时,一定要按库(sdk)配置好才build。

【7.使用鸿洋的适配库】:

报xml等错误:原因

1)布局中引入的是sdk的布局还是Android.widget的(可能性小)
2)清单中没有添加<meta......>宽高等

【8.每个module中添加arouter时】

都要有

 //ARouter
annotationProcessor "com.alibaba:arouter-compiler:$arouter_compiler_version"

和(否则报错--且错误中有提示)

javaCompileOptions {
      annotationProcessorOptions {
          arguments = [moduleName: project.getName()]
      }
}

【9.RecyclerView】与scroll view冲突,用Nest Scroll view,并且RecyclerView垂直不可滑动。

RecyclerView 去掉滑动边缘阴影效果android:overScrollMode="never"
LinearLayoutManager不能多个RecyclerView公用

LinearLayoutManager mLinearLayoutManager = new LinearLayoutManager(mContext) { 
    @Override 
    public boolean canScrollVertically() { 
        return false; 
    } };
    
----设置RecyclerView滑动监听-----
//只适用于NestedScrollingChild的子类,就是RV外层是Nest...
//recyclerView.setNestedScrollingEnabled(false);  
//app:reverseLayout="true"  //是否从右到左布局

LayoutManager的滑动方法
scrollToPositionWithOffset(int position, int offset)
setSmoothScrollbarEnabled(boolean)

RecyclerView提供了几种移动的方法
scrollToPosition (直接闪现至某一位位置)
scrollTo
scrollBy
smoothScrollBy
smoothScrollToPosition  (惯性滑动至某一位置)
//继承XXXLayoutManager,重写canScrollXXX,
public class MyLinearLayoutManager extends LinearLayoutManager {

    private boolean canScroll = true;

    public MyLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    public MyLinearLayoutManager(Context context, int spanCount) {
        super(context, spanCount);
    }

    public MyLinearLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {
        super(context, spanCount, orientation, reverseLayout);
    }

    @Override
    public boolean canScrollVertically() {
        return canScroll && super.canScrollVertically();
    }

    @Override
    public boolean canScrollHorizontally() {
        return super.canScrollHorizontally();
    }

    /**
     * 设置是否可以滑动
     */
    public void setCanScroll(boolean canScroll) {
        this.canScroll = canScroll;
    }
}

【10.代码设置DrawableLeft】

Drawable drawableLeft = getResources().getDrawable(R.mipmap.weixin_pay);
//img.setBounds(0, 0, img.getMinimumWidth(), img.getMinimumHeight());
tvEnd.setCompoundDrawablePadding(20);
textView.setCompoundDrawablesWithIntrinsicBounds(drawableLeft, null, null, null);

【11.高效加载大图】

获取应用程序最高可用内存

int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
Log.d("TAG", "Max memory is " + maxMemory + "KB");

0.根据图片来源,选择BitmapFactory的解析方法
1.禁止为Bitmap分配内存
2.获取图片长宽高和MIME
3.计算合适的inSampleSize(压缩比例)
4.再次解析

【12.Button去除阴影】

style="?android:attr/borderlessButtonStyle"
或者在styles里parent="@style/Widget.AppCompat.Button.Borderless"
但是点击没有样式效果了
去除button大写字母:android:textAllCaps="false"

【13.Recyclerview水波纹效果】

在Item的背景添加
android:background="?android:attr/selectableItemBackground"

【】
editText、checkBox在列表中直接使用是有问题的
如果非要使用,给他们设置tag

【14.高度】

状态栏:24dp,标题栏:48dp,或者?android:attr/actionBarSize,底部导航栏:56dp
clipChildren:false---是否限制子View在其范围内,默认的时候是true

【15.LinearLayout添加下划线等】

android:divider="@drawable/gray_line"
android:showDividers="end"

【16.Int转化错误】

NumberFormatException: Invalid int: "25.0"
字符串在转数据类型时,如float等,最好添加try catch ,否则在第一次输入 . 时崩掉

【17.自定义view】

RL.setBackgroundResource(R.color/drawable.color_white)//直接用此,
//不要用getResource.getColor()
RL.setBackgroundResource(getResource.getColor(R.color.color_white))//崩掉

【18.RelativeLayout与LinearLayout】

(1)RelativeLayout慢于LinearLayout是因为它会让子View调用2次measure过程,而后者只需一次,但是有weight属性存在时,后者同样会进行两次measure。
(2)RelativeLayout的子View如果高度和RelativeLayout不同,会引发效率问题,可以使用padding代替margin以优化此问题。
(3)在不响应层级深度的情况下,使用Linearlayout而不是RelativeLayout。
采用RelativeLayout并不会降低层级深度,因此这种情况下使用LinearLayout效率更高。
为开发者默认新建RelativeLayout是希望开发者能采用尽量少的View层级,很多效果是需要多层LinearLayout的嵌套,这必然不如一层的RelativeLayout性能更好。因此我们应该尽量减少布局嵌套,减少层级结构,使用比如viewStub,include等技巧。
现在也基本是用 ConstraintLayout

【19.自动保存密码】

  1. 可以保存登录后返回的token和账号,不保存密码,下次启动自动使用token验证就好。token过期后账号可以自动填上,密码仍然要重新输入。
  2. 把密码加密后保存。

【20.定义Bean类时,最好写public型而非getter/setter方法】

[https://segmentfault.com/q/1010000008022583]()
[https://developer.android.com/training/articles/perf-tips#internal_get_set]()
[https://www.jianshu.com/p/c73041a62111]()

【21.SP的commit与apply】

  1. commit是原子提交到数据库(硬件磁盘),所以从提交数据到存在Disk中都是同步过程,中间不可打断。有一个boolean的返回值,永远都是最后一个调用commit方法的editor变更了最后的数据值。
  2. apply方法的原子操作是原子提交的内存中,而非数据库,所以在提交到内存中时不可打断,之后再异步提交数据到数据库中,因此也不会有相应的返回值。
  3. commit提交是同步过程,效率会比apply异步提交的速度慢,但是apply没有返回值,永远无法知道存储是否失败。
  4. 在不关心提交结果是否成功的情况下,优先考虑apply方法。

【22.LinkedList和ArrayList相比】

1、LinkedList插入删除相对较快,而查询较慢;
2、ArrayList插入删除相对较慢,而查询很快(详细可查看从源码的角度分析List与Set的区别);

【23.SP】见【95】

卸载时,应用的SharedPreferences文件会被删除,而当覆盖安装时,则会被保留。因此,想要对不同版本区分,可以尝试key+version的方式。

【24.】7.0读写请求权限【见56\64】

  1. 清单
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 创建和删除文件 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<!--安装包时需要-->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<!--常用的-->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
  1. 请求权限
private void requestPermission() {
    boolean isGranted = true;
    //23是6.0(以后需要动态申请)
    if (Build.VERSION.SDK_INT >= 23) {
        if (this.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            //如果没有写sd卡权限
            isGranted = false;
        }
        if (this.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            isGranted = false;
        }
        if (!isGranted) {
            this.requestPermissions(
                    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    7);
        } else {
            //以后每次授予权限后的逻辑
            //startDown();
        }
    } else {
        //小于6.0的权限直接再清单里就行
        //startDown();
    }
}
  1. 第一次请求到权限后
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    //读写文件--安装apk
    if (requestCode == 7) {
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            //第一次授予权限后的逻辑
            //startDown();
        } else {
            // Permission Denied的逻辑
            //startDown();
        }
        return;
    }
    if (requestCode == Config.CODE_CAMERA) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                openCamera();
            } else {
                // Permission Denied
//                Toast.makeText(this, "Permission Denied", Toast.LENGTH_SHORT).show();
            }
            return;
    }
    if (requestCode == Config.CODE_MULTI_PERMISSION) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                operAlbum();
//                startActivityForResult(new Intent(this, ScanActivity.class),Config.QRCODE_REQUESTCODE);         //拨打电话
            } else {
                // Permission Denied
//                Toast.makeText(this, "Permission Denied", Toast.LENGTH_SHORT).show();
            }
            return;
    }
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
  1. 7.0 xml权限
//再res下新建xml文件夹,创建filepaths.xml文件(名字自定义),如下:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">

    <!--Android7.0调用相机,用于指定共享的目录-->
    <external-path
        name="image"
        path="." />

    <external-path
        name="files_root"
        path="."/>

    <!--external-path 表示用来指定共享路径的-->
    <!--name 随便取,只是一个标签-->
    <!--path 这个比较重要,如果不设置,则表示将整个 SD 卡进行共享,然后制定了,比如 path=”Pictrues”那么,就只共享 sd卡下的 Pictures 文件夹-->

</paths>
  1. 清单添加
<application>
。。。
<provider
    android:name="androidx.core.content.FileProvider"   //AndroidX用此
    android:name="android.support.v4.content.FileProvider"
    <!--这里权限自定义但唯一,后面要用到-->
    android:authorities="com.zxx.utils.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        <!--这里就是上面的文件-->
        android:resource="@xml/filepaths" />
</provider>
</application>
  1. 打开安装文件(使用-照相同理)
//4. 当后台操作结束时,此方法将会被调用,计算结果将做为参数传递到此方法中,直接将结果显示到UI组件上。
@Override
protected void onPostExecute(File result) {
     if (result != null) {
         // Intent broadcast = new Intent(Constants.INTENT_ACTION_UPDATE_FINISHED);
         // sendBroadcast(broadcast);
         Intent intent = new Intent(Intent.ACTION_VIEW);

         //如果在Android7.0以上,使用FileProvider获取Uri
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
             intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
             //这里就用到了上面的权限
             Uri uri = FileProvider.getUriForFile(context, "com.zxx.utils.fileprovider", file);
             intent.setDataAndType(uri, "application/vnd.android.package-archive");
        } else {
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             intent.setDataAndType(Uri.fromFile(result), "application/vnd.android.package-archive");
        }
        //跳转到安装界面
        startActivity(intent);
    }
}
//至此安装完成
  1. 打开相机 -- 相册
public void openCamera() {
    //用于保存调用相机拍照后所生成的文件
    File cameraPath = new File(Environment.getExternalStorageDirectory().getPath(), System.currentTimeMillis() + ".jpg");
    ZLog.e("cameraPath=" + cameraPath.toString());

    //跳转到调用系统相机
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

    //如果在Android7.0以上,使用FileProvider获取Uri
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        intent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        //这里就用到了上面的权限
        Uri uri = FileProvider.getUriForFile(context, "com.zxx.utils.fileprovider", cameraPath);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);

    } else {
        // 把文件地址转换成Uri格式
        //否则使用Uri.fromFile(file)方法获取Uri
        intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(cameraPath));
        ZLog.e("Tag--99" + cameraPath.toString());
    }
    setCameraPath(cameraPath);  //添加

    ((Activity) context).startActivityForResult(intent, Config.CAMERA_REQUESTCODE);
}
public void operAlbum() {
        Intent intent = new Intent(Intent.ACTION_PICK);
        intent.setType("image/*");
        intent.addCategory(Intent.CATEGORY_OPENABLE);

        //根据版本号不同使用不同的Action:http://blog.csdn.net/nbalichaoq/article/details/51992151
//        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
            intent.setAction(Intent.ACTION_GET_CONTENT);//返回的Uri类型可以是content:// ;file://  ;http://中的一种(适配小米)
//        } else {
//            intent.setAction(Intent.ACTION_OPEN_DOCUMENT);//此处对小米手机没有用,只有content://一种
//        }
        ((Activity) context).startActivityForResult(Intent.createChooser(intent, null) , Config.ALBUM_REQUESTCODE) ;
//        ((Activity) context).startActivityForResult(intent, Config.ALBUM_REQUESTCODE);
}
  1. 相机-与相册回调
String Setting.SEVEN_URI===就是上面的权限

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_OK) {
        switch (requestCode) {
            case Config.CAMERA_REQUESTCODE:           //开启相机
                //用相机返回的照片去调用剪裁也需要对Uri进行处理(Android7.0)
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    Uri uri = FileProvider.getUriForFile(this,Setting.SEVEN_URI , cameraPath);
                    ImageDisplayer.cropPhoto(this, uri);
                    ZLog.e("Android在7.0以上");

                } else {
                    ImageDisplayer.cropPhoto(this, Uri.fromFile(cameraPath));
                    ZLog.e("Android在7.0以下");
                }
                break;
            case Config.ALBUM_REQUESTCODE:          //打开相册
                if (data != null) {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        ImageDisplayer.handleImgeOnKitKat(this, data);       //7.0 content开头

                    } else {
                        Uri uri = data.getData();
                        ZLog.e("uri=intent.getData :" + uri);
                        ImageDisplayer.cropPhoto(this, uri);
                    }
                }
                break;
            case Config.CROP_REQUEST_CODE:          //裁剪完的图片
                Bundle bundle = data.getExtras();
                if (bundle != null) {
                    //在这里获得了剪裁后的Bitmap对象,可以用于上传
                    Bitmap cropBitmap = bundle.getParcelable("data");

                    //对得到的Bitmap进行尺寸缩放
                    Bitmap cutBitmap = new ImageDisplayer(100, 100)
                            .autoResizeFromBitmap(cropBitmap);

                    //存储到本地
                    String filePath = controller.saveBitmap(cutBitmap);
                    ZLog.e("filePath=" + filePath);
                }
                break;

            case Config.QRCODE_REQUESTCODE:         //二维码
                Log.e("Tag", "扫描的结果为:" + data.getStringExtra("result"));
                break;
        }
    }
}
//Uri不同,自动下载安装
private void installApk(File file) {
    if (!file.exists()) {
        return;
    }
    Uri uri = null;
    Intent install = new Intent(Intent.ACTION_VIEW);
    install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        //AUTHORITY_TAG 即为 provider 注册中的 android:authorities 值。
        uri = FileProvider.getUriForFile(mContext, AUTHORITY_TAG, file);
        // 给目标应用一个临时授权
        install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    } else {
        uri = Uri.fromFile(file);
    }
    install.setDataAndType(uri, "application/vnd.android.package-archive");
    mContext.startActivity(install);
}

android 8.0开始
增加了安装未知权限的限制,于是需要在 mainfast.xml中添加安装未知应用的权限:
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>

【这里插一句】同一Android手机安装不同debug(修改包名了)

[https://blog.csdn.net/juhua2012/article/details/79671112]()
应用里面包含有ContentProvider 或者 FileProvider等等其他的的provider的使用,那么就动态获取applicationId。

  1. 改变生成app的包名:在 app 下的 build.gradle 的打包配置里增加 applicationIdSuffix
buildTypes {
          release {
              minifyEnabled false
              proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
              signingConfig signingConfigs.config
          }
          debug {
              applicationIdSuffix '.debug' //增加包名后缀
          }
}
//比较全 看wms项目
 buildTypes {
        debug {
            buildConfigField("boolean", "LOG_DEBUG", "true")
            minifyEnabled false
            resValue 'string', 'app_name', 'WMS测试'
            applicationIdSuffix '.debug' //增加包名后缀
            buildConfigField 'String', "SERVER_URL", '"http://192.168.0.4:9214/app/"'
//            buildConfigField 'String', "SERVER_URL", '"http://192.168.0.212:9214/app/"'
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            // 不移除无用的resource文件
        }

        debugbeta {
            debuggable = true
            buildConfigField("boolean", "LOG_DEBUG", "true")
            minifyEnabled false
            resValue 'string', 'app_name', 'WMS_Beta'
            applicationIdSuffix '.debugbeta' //增加包名后缀
            buildConfigField 'String', "SERVER_URL", '"http://192.168.0.212:9214/app/"'
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            // 不移除无用的resource文件
            signingConfig signingConfigs.release
        }

        release {
            buildConfigField("boolean", "LOG_DEBUG", "false")
            minifyEnabled false
            resValue 'string', 'app_name', 'WMS'
            buildConfigField 'String', "SERVER_URL", '"http://正室地址/"'
            applicationIdSuffix '.release' //增加包名后缀
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            // 移除无用的resource文件
            signingConfig signingConfigs.release
        }
}
  1. 动态获取AppID
<provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_provider" />
</provider>

Uri imageUri=null;
if (Build.VERSION.SDK_INT >=  Build.VERSION_CODES.N){
    imageUri = FileProvider.getUriForFile(MyActivity.this,getApplication().getPackageName()+".fileprovider",outputImage);
}else {
    imageUri = Uri.fromFile(outputImage);
}

Android打电话不一定要申请权限

第一种是直接跳转到拨打电话界面,并将电话号码带过去,这里不需要申请权限,就可以直接跳转到拨号界面

Intent intent = new Intent(Intent.ACTION_DIAL);
Uri data = Uri.parse("tel:" + "135xxxxxxxx");
intent.setData(data);
startActivity(intent);

第二种是直接播出电话,需要在AndroidManifest文件中加这个权限,如果api>=23还需要申请动态权限

Intent intent = new Intent(Intent.ACTION_CALL);
Uri data = Uri.parse("tel:" + "135xxxxxxxx");
intent.setData(data);
startActivity(intent);

【25.】返回第一个Activity

Intent intent = new Intent(this, FirstActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
//所以
清单:android:launchModel = "singleTask"

如果intent对象包含FLAG_ACTIVITY_CLEAR_TOP 标记,当目标task中已存在与接收该intent对象的 activity类型相同的activity实例存在时,所有位于该activity对象上面的activity将被清空,这样接收该intent的 activity就位于栈顶,可以响应到来的intent对象。
如果目标activity的运行模式为standard(默认),则目标activtiy也会被清空。因为当运行模式为standard时,总会创建新的activity对象来接收到来的intent对象。

//或者:清单:
android:launchModel = "singleTask"

Intent intent= new Intent(this, 首页Activity.class);  
startActivity(intent);  

【26。返回Login】

Intent intent = new Intent(this, LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
清单:android:launchModel = "singleTask"

//用Clear_Top是清除 LoginActivity之上的Activity
A-B-Login-D-E:从E跳转到Login则DE清除,AB还在
adb
adb 
adb devices   //列出所有设备
adb kill-server    //杀死所有adb服务
adb start-server   //重启adb服务
gradle dependencies

cd ..  //返回上级目录

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
4009 0
怎么设置阿里云服务器安全组?阿里云安全组规则详细解说
阿里云服务器安全组设置规则分享,阿里云服务器安全组如何放行端口设置教程
6362 0
阿里云服务器ECS远程登录用户名密码查询方法
阿里云服务器ECS远程连接登录输入用户名和密码,阿里云没有默认密码,如果购买时没设置需要先重置实例密码,Windows用户名是administrator,Linux账号是root,阿小云来详细说下阿里云服务器远程登录连接用户名和密码查询方法
2171 0
windows server 2008阿里云ECS服务器安全设置
最近我们Sinesafe安全公司在为客户使用阿里云ecs服务器做安全的过程中,发现服务器基础安全性都没有做。为了为站长们提供更加有效的安全基础解决方案,我们Sinesafe将对阿里云服务器win2008 系统进行基础安全部署实战过程! 比较重要的几部分 1.
4963 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
5676 0
阿里云ECS云服务器初始化设置教程方法
阿里云ECS云服务器初始化是指将云服务器系统恢复到最初状态的过程,阿里云的服务器初始化是通过更换系统盘来实现的,是免费的,阿里云百科网分享服务器初始化教程: 服务器初始化教程方法 本文的服务器初始化是指将ECS云服务器系统恢复到最初状态,服务器中的数据也会被清空,所以初始化之前一定要先备份好。
10712 0
如何设置阿里云服务器安全组?阿里云安全组规则详细解说
阿里云安全组设置详细图文教程(收藏起来) 阿里云服务器安全组设置规则分享,阿里云服务器安全组如何放行端口设置教程。阿里云会要求客户设置安全组,如果不设置,阿里云会指定默认的安全组。那么,这个安全组是什么呢?顾名思义,就是为了服务器安全设置的。安全组其实就是一个虚拟的防火墙,可以让用户从端口、IP的维度来筛选对应服务器的访问者,从而形成一个云上的安全域。
3807 0
阿里云服务器ECS登录用户名是什么?系统不同默认账号也不同
阿里云服务器Windows系统默认用户名administrator,Linux镜像服务器用户名root
721 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,云吞铺子总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系统盘、创建快照、配置安全组等操作如何登录ECS云服务器控制台? 1、先登录到阿里云ECS服务器控制台 2、点击顶部的“控制台” 3、通过左侧栏,切换到“云服务器ECS”即可,如下图所示 通过ECS控制台的远程连接来登录到云服务器 阿里云ECS云服务器自带远程连接功能,使用该功能可以登录到云服务器,简单且方便,如下图:点击“远程连接”,第一次连接会自动生成6位数字密码,输入密码即可登录到云服务器上。
16273 0
+关注
zerosboy
一切从零开始,一切化归于零
5
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载