zoukankan      html  css  js  c++  java
  • Android code wiki

    Android code wiki

    Tip1:
    类的全局静态变量的使用,这样可以静态变量只分配一次内存,可以不通过类的对象也就是可以通过类名直接使用该变量。(使用场景:Request_Code ,Result_Code,Log Tag,权限名字,Activity之间传递参数Name eg:bundle,公用参数名字,接受回调的参数( eg: getIntent() ),可以防止分配内存 etc)
     
    /*
    * Copyright (C) 2015 The Android Open Source Project
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
    * http://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    * See the License for the specific language governing permissions and
    * limitations under the License.
    */

    package com.android.cts.permissionapp;

    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.util.Log;

    import java.lang.Override;

    /**
    * A simple activity that requests permissions and returns the result.
    */
    public class PermissionActivity extends Activity {
    private static final String TAG = "PermissionActivity";

    private static final String ACTION_CHECK_HAS_PERMISSION
    = "com.android.cts.permission.action.CHECK_HAS_PERMISSION";
    private static final String ACTION_REQUEST_PERMISSION
    = "com.android.cts.permission.action.REQUEST_PERMISSION";
    private static final String ACTION_PERMISSION_RESULT
    = "com.android.cts.permission.action.PERMISSION_RESULT";
    private static final String EXTRA_PERMISSION
    = "com.android.cts.permission.extra.PERMISSION";
    private static final String EXTRA_GRANT_STATE
    = "com.android.cts.permission.extra.GRANT_STATE";
    private static final int PERMISSION_ERROR = -2;
    private static final int PERMISSIONS_REQUEST_CODE = 100;

    private String mPermission;

    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    final Intent received = getIntent();
    Log.d(TAG, "Started with " + received);

    final String action = received.getAction();
    mPermission = received.getStringExtra(EXTRA_PERMISSION);
    if (ACTION_REQUEST_PERMISSION.equals(action)) {
    Log.d(TAG, "Requesting permission " + mPermission);
    requestPermissions(new String[] {mPermission}, PERMISSIONS_REQUEST_CODE);
    } else if (ACTION_CHECK_HAS_PERMISSION.equals(action)) {
    Log.d(TAG, "Checking permission " + mPermission);
    sendResultBroadcast(checkSelfPermission(mPermission));
    } else {
    Log.w(TAG, "Unknown intent received: " + received);
    finish();
    }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions,
    int[] grantResults) {
    if (requestCode != PERMISSIONS_REQUEST_CODE ||
    permissions.length != 1 ||
    !permissions[0].equals(mPermission)) {
    Log.d(TAG, "Received wrong permissions result");
    sendResultBroadcast(PERMISSION_ERROR);
    } else {
    Log.d(TAG, "Received valid permission result: " + grantResults[0]);
    sendResultBroadcast(grantResults[0]);
    }
    }

    private void sendResultBroadcast(int result) {
    Log.d(TAG, "Sending result broadcast: " + result);
    Intent broadcast = new Intent(ACTION_PERMISSION_RESULT);
    broadcast.putExtra(EXTRA_GRANT_STATE, result);
    sendBroadcast(broadcast);
    finish();
    }
    }
     
    Tip 2:
    namespace的小技巧,在Android 中最常用到的namespace 就是在XML里面的android:***,这样的写法非常方便,现在要说的不是android 这个namespace,是另外一个namespace tools.它非常有用。
     
    tools的URI的全称是”http://schemas.android.com/tools”,常用的方式是声明整个URI以后用前缀 tools 来在XML文件里面使用。tools有关的所有属性不会影响应用的运行和应用的大小,所有的tools属性会被gradle 过滤掉的当编译打包的时候。
     
    快速添加tools的步骤:
    在XML的根里面添加,只要敲出 toolsNS 和 TAB (Android Studio)就会自动添加tools这个namespace的全URI.
     
     
    tools使用方法:
    Android Studio的XML里面现在还不提供对tools所有属性的自动补全,最简单的办法 就是 复制android:**,然后换一下namespace,把android 换成tools即可。
     
    有时候为了开发方便而不影响用户的体验可以使用它,在XML里面声明一个TextView,但是为了预览更方便会设置android:text=“我是预览的文字,我一直在,不管是否编译”,这样就会预览到文字的效果,但是,如果只是在XML预览的时候能看到,编译运行以后就看不到,怎么实现呢?这时候就用到了tools这个神奇的工具,可以这样写tools:text="我是预览的文字,我不是一直在,编译我就消失啦” 来代替 android:text=“我是预览的文字,我一直在,不管是否编译”。
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    tools:text="我是预览的文字,编译我就消失啦" />

    </LinearLayout>
     
    同理,为了预览方便而编译以后不需要的时候任何场景都可以使用tools来实现。有时候为了预览的时候某些属性enable,但是运行的时候unenable。可以进行android namespace所有属性覆盖的,除了自定义View的属性。
     
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
    android:id="@+id/listView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:fastScrollAlwaysVisible="true"
    tools:fastScrollAlwaysVisible="false" />

    </LinearLayout>
     
     
    关于@TargetApi,在代码里面,经常会遇见的一个注解,用tools也是在XML里面可以实现的,比如:tools:targetApi,可以用integer 或者版本的名字 来声明版本信息。
     
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    tools:layout_height="match_parent"
    tools:targetApi="M"
    tools:text="Mastering ToolsNs" />

    </LinearLayout>
     
     
    当Lint检查 string resources是否正确的时候,经常会有警告信息,如果有强迫症并且应用没有走国际化,那么你可以这样来。
     
    <resources xmlns:tools="http://schemas.android.com/tools"
    tools:locale="es">
     
     
    关于预览fragment或者自定义view。可以在一个布局文件里面这样写。下面是预览Booksfragment,不需要编译运行,也不需要模拟器就可以看到预览的效果啦。
     
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <fragment
    android:name="com.alexsimo.mastertoolsnamespace.BooksFragment"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:layout="@layout/fragment_books" />

    </LinearLayout>
     
    更复杂的多层级预览,也是可以达到的。比如预览一个Activity里面的一个fragment的一个ListView对应的每个Item,如果,不编译运行在模拟器或者自己的设备上,应该是看不到效果的,但是,有了tools,一切都变得简单了。
     
    activity_main:
     
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <fragment
    android:name="com.alexsimo.mastertoolsnamespace.BooksFragment"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:layout="@layout/fragment_book" />

    </LinearLayout>
     
     
    fragment_book:
     
    tools:listitem=“” tools:listheader,tools:listfooter,预览ListView是非常有用的,但是对于RecyclerView 没有header和footer
     
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/list"
    android:name="com.alexsimo.mastertoolsnamespace.BooksFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginLeft="16dp"
    android:layout_marginRight="16dp"
    app:layoutManager="LinearLayoutManager"
    tools:context="com.alexsimo.mastertoolsnamespace.BooksFragment"
    tools:listitem="@layout/fragment_book_list_item" />
     
    fragment_book_list_item:
     
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <ImageView
    android:id="@+id/imageView"
    android:layout_width="150dp"
    android:layout_height="150dp"
    tools:src="@android:drawable/ic_media_play" />

    <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
    android:id="@+id/id"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="@dimen/text_margin"
    android:textAppearance="?attr/textAppearanceListItem"
    tools:text="My book title" />

    <TextView
    android:id="@+id/content"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="@dimen/text_margin"
    android:textAppearance="?attr/textAppearanceListItem"
    tools:text="My book description" />
    </LinearLayout>

    </LinearLayout>
     
    这时候预览activity_main,如下:
     
     
    关于预览layout 的 menus ,一般在Activity中定义 Activity.onCreateOptionsMenu(),为了预览可以用 tools:menu="comma separated menu IDs” ,设置Toolbar navigation mode,可以这样,tools:actionBarNavMode="standard|list|tabs”。
     
     
     
    Tip3:
     
    关于软键盘的问题,常用的软键盘各种模式,比如,为了适应页面大小,可以android:windowSoftInputMode="adjustResize"
    如果不喜欢XML配置,喜欢代码设置,那么你可以这样来:
    activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
     
    自定义View展示PDF文件,PDF文件可以编辑,那么view点击编辑状态,软键盘弹出,这时候设置adjustResize就无效了,因为这个页面是全屏的,关于Fullscreen mode,g官方解释是这样的:
     
    If the window's layout parameter flags include FLAG_FULLSCREEN, this value for softInputMode will be ignored; the window will not resize, but will stay fullscreen.
     
    总而言之和键盘的adjustResize冲突了,这时候键盘就出问题了。
     
    这时候可以监听键盘,然后手动计算设置高度了。
     
     
    // Threshold for minimal keyboard height.
    final int MIN_KEYBOARD_HEIGHT_PX = 150;
     
    // Top-level window decor view.
    final View decorView = activity.getWindow().getDecorView();
     
    // Register global layout listener.
    decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    private final Rect windowVisibleDisplayFrame = new Rect();
    private int lastVisibleDecorViewHeight;
     
    @Override
    public void onGlobalLayout() {
    // Retrieve visible rectangle inside window.
    decorView.getWindowVisibleDisplayFrame(windowVisibleDisplayFrame);
    final int visibleDecorViewHeight = windowVisibleDisplayFrame.height();
     
    // Decide whether keyboard is visible from changing decor view height.
    if (lastVisibleDecorViewHeight != 0) {
    if (lastVisibleDecorViewHeight > visibleDecorViewHeight + MIN_KEYBOARD_HEIGHT_PX) {
    // Calculate current keyboard height (this includes also navigation bar height when in fullscreen mode).
    int currentKeyboardHeight = decorView.getHeight() - windowVisibleDisplayFrame.bottom;
    // Notify listener about keyboard being shown.
    listener.onKeyboardShown(currentKeyboardHeight);
    } else if (lastVisibleDecorViewHeight + MIN_KEYBOARD_HEIGHT_PX < visibleDecorViewHeight) {
    // Notify listener about keyboard being hidden.
    listener.onKeyboardHidden();
    }
    }
    // Save current decor view height for the next call.
    lastVisibleDecorViewHeight = visibleDecorViewHeight;
    }
    });
     
     
     
     
    Tip4: 关于遍历
     
    在开发中,遍历集合,搜集信息,是最常见的代码块,遍历中,如果中间出现异常,是不是遍历就终止了,但是如果遍历出现异常还要能继续执行剩下的条目,怎么办呢,这时候就用到了异常处理机制,如下:
     
     
    String routes = intent.getStringExtra(packageName + ".routes");
    if (routes != null) {
    String[] routeArray = routes.split(",");
    for (int i = 0; i < routeArray.length; i++) {
    String[] prefixAndMask = routeArray[i].split("/");
    try {
    InetAddress address = InetAddress.getByName(prefixAndMask[0]);
    int prefixLength = Integer.parseInt(prefixAndMask[1]);
    builder.addRoute(address, prefixLength);
    } catch (UnknownHostException|NumberFormatException|
    ArrayIndexOutOfBoundsException e) {
    continue;
    }
    }
    }
     
    建议上面这种写法,catch捕获以后,continue;同时,关于异常的另外一个用处,当return用,可以直接返回,如下:
     
     
     
    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
    throw new RuntimeException("Operation not supported");
    }
     
     
     
    Tip5: 关于调用ShareCompat Intent,代码如下:
     
     
    // Create share intent
    Intent shareIntent = ShareCompat.IntentBuilder.from(this)
    .setText(getShareText(coupon))
    .setType("image/jpeg")
    .setStream(coupon.mImageUri)
    .setChooserTitle(getString(R.string.redeem_using))
    .createChooserIntent();
    startActivity(shareIntent);
     
     
    关于格式化展示信息的时候,一般都是用String的format来进行,这里介绍另外一种:
     
     
    if (TextUtils.isEmpty(SENDER_NAME)) {
    return getString(R.string.message_format_without_sender,
    coupon.mTitle, coupon.mSubtitle);
    } else {
    // Otherwise, use the other string template and pass in the {@link #SENDER_NAME} too
    return getString(R.string.message_format_with_sender, SENDER_NAME,
    coupon.mTitle, coupon.mSubtitle);
    }
     
    这里会调用Context里面的getString()方法来实现,前面的格式化的format如下,然后传入对于需要格式化的标题和子标题就OK了
     
     
    <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <!--
    Template string with coupon title, subtitle, and sender name for the text to use
    when the coupon is shared with other apps. [CHAR LIMIT=NONE]
    -->
    <string name="message_format_without_sender">Excited to redeem my coupon! <xliff:g id="coupon_title">%s</xliff:g> - <xliff:g id="coupon_subtitle">%s</xliff:g> #justforus</string>
     
    <!--
    Template string with coupon title, subtitle, and sender name for the text to use
    when the coupon is shared with other apps. [CHAR LIMIT=NONE] 写注释是个好习惯
    -->
    <string name="message_format_with_sender">Excited to redeem my coupon with <xliff:g id="coupon_title">%s</xliff:g>! <xliff:g id="coupon_title">%s</xliff:g> - <xliff:g id="coupon_subtitle">%s</xliff:g> #justforus</string>
     
    </resources>
     
     
     
    Tip5: 关于Adapter
     
    /**
    * Adapter for grid of coupons.
    */
    private static class CouponAdapter extends BaseAdapter {
     
    private LayoutInflater mInflater;
    private List<Coupon> mAllCoupons;
     
    /**
    * Constructs a new {@link CouponAdapter}.
    *
    * @param inflater to create new views
    * @param allCoupons for list of all coupons to be displayed
    */
    public CouponAdapter(LayoutInflater inflater, List<Coupon> allCoupons) {
    if (allCoupons == null) {
    throw new IllegalStateException("Can't have null list of coupons");
    }
    mAllCoupons = allCoupons;
    mInflater = inflater;
    }
     
    @Override
    public int getCount() {
    return mAllCoupons.size();
    }
     
    @Override
    public Coupon getItem(int position) {
    return mAllCoupons.get(position);
    }
     
    @Override
    public long getItemId(int position) {
    return position;
    }
     
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
     
    //缓存策略的另外一种写法
     
    View result = convertView;
    if (result == null) {
    //注意mInflater的来源,是在Activity的setContextView中这样写的:
    // Fetch the {@link LayoutInflater} service so that new views can be created
    // LayoutInflater inflater = (LayoutInflater) getSystemService(
    // Context.LAYOUT_INFLATER_SERVICE);
    result = mInflater.inflate(R.layout.grid_item, parent, false);
    }
     
    // Try to get view cache or create a new one if needed
    ViewCache viewCache = (ViewCache) result.getTag();
    if (viewCache == null) {
    viewCache = new ViewCache(result);
    result.setTag(viewCache);
    }
     
    // Fetch item
    Coupon coupon = getItem(position);
     
    // Bind the data
    viewCache.mTitleView.setText(coupon.mTitle);
    viewCache.mSubtitleView.setText(coupon.mSubtitle);
    viewCache.mImageView.setImageURI(coupon.mImageUri);
     
    return result;
    }
    }
     
    /**
    * Cache of views in the grid item view to make recycling of views quicker. This avoids
    * additional {@link View#findViewById(int)} calls after the {@link ViewCache} is first
    * created for a view. See
    * {@link CouponAdapter#getView(int position, View convertView, ViewGroup parent)}.
    */
    private static class ViewCache {
     
    /** View that displays the title of the coupon */
    private final TextView mTitleView;
     
    /** View that displays the subtitle of the coupon */
    private final TextView mSubtitleView;
     
    /** View that displays the image associated with the coupon */
    private final ImageView mImageView;
     
    /**
    * Constructs a new {@link ViewCache}.
    *
    * @param view which contains children views that should be cached.
    */
    private ViewCache(View view) {
    mTitleView = (TextView) view.findViewById(R.id.title);
    mSubtitleView = (TextView) view.findViewById(R.id.subtitle);
    mImageView = (ImageView) view.findViewById(R.id.image);
    }
    }
     
    /**
    * 关于适配器里面数据bean对象问题,如果只是纯粹展示,而不需要改变bean对象的属性,那么推荐下面这种方式,如果需要改变
    * bean对象的属性,那么还是用常见的get set方法实现.
    */
    private static class Coupon {
     
    /** Title of the coupon. */
    private final String mTitle;
     
    /** Description of the coupon. */
    private final String mSubtitle;
     
    /** Content URI of the image for the coupon. */
    private final Uri mImageUri;
     
    /**
    * Constructs a new {@link Coupon}.
    *
    * @param titleString is the title
    * @param subtitleString is the description
    * @param imageAssetFilePath is the file path from the application's assets folder for
    * the image associated with this coupon
    */
    private Coupon(String titleString, String subtitleString, String imageAssetFilePath) {
    mTitle = titleString;
    mSubtitle = subtitleString;
    mImageUri = Uri.parse("content://" + AssetProvider.CONTENT_URI + "/" +
    imageAssetFilePath);
    }
    }
     
     
    Tip6: 关于应用的全局常量
     
     
    package com.example.android.apprestrictionenforcer;
     
    public interface Constants {
     
    /**
    * Package name of the AppRestrictionSchema sample.
    */
    public static final String PACKAGE_NAME_APP_RESTRICTION_SCHEMA
    = "com.example.android.apprestrictionschema";
     
    }
     
    为什么以接口的形式定义,而不用class定义呢,这里要说明一下用接口的好处,因为Java语言中要求,接口中定义的变量默认是public static final型,且必须给其初始值,所以实现类中不能重新定义,也不能改变其值,如果用到全局常量的定义的时候,这时候定义Constants,就限制了常量的类型,static final,多了一步校验。
     
    题外话:接口更多的是在系统架构设计方法发挥作用,主要用于定义模块化之间的通信契约。(符合这种理念)
    而抽象类在代码实现方面发挥作用,可以实现代码的重用。
     
     
    Tip7: 关于网络
     
    检查网络状态代码片:
     
     
    /**
    * Check whether the device is connected, and if so, whether the connection
    * is wifi or mobile (it could be something else).
    */
    private void checkNetworkConnection() {
    // BEGIN_INCLUDE(connect)
    ConnectivityManager connMgr =
    (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeInfo = connMgr.getActiveNetworkInfo();
    if (activeInfo != null && activeInfo.isConnected()) {
    wifiConnected = activeInfo.getType() == ConnectivityManager.TYPE_WIFI;
    mobileConnected = activeInfo.getType() == ConnectivityManager.TYPE_MOBILE;
    if(wifiConnected) {
    Log.i(TAG, getString(R.string.wifi_connection));
    } else if (mobileConnected){
    Log.i(TAG, getString(R.string.mobile_connection));
    }
    } else {
    Log.i(TAG, getString(R.string.no_wifi_or_mobile));
    }
    // END_INCLUDE(connect)
    }
     
     
    获取屏幕的一切信息,来自这个类:
     
    getResources().getDisplayMetrics() 得到
    DisplayMetrics 这个类,就可以获取到一切有关设备屏幕大小,密度等信息了...
     
    // eg: Calculate radiuses in px from dp based on screen density
    float density = getResources().getDisplayMetrics().density;
     
    关于自定义View中随机颜色的写法:
     
    定义十六进制的颜色
     
    public final int[] COLORS = {
    0xFF33B5E5, 0xFFAA66CC, 0xFF99CC00, 0xFFFFBB33, 0xFFFF4444,
    0xFF0099CC, 0xFF9933CC, 0xFF669900, 0xFFFF8800, 0xFFCC0000
    };
     
    这样就可以根据id动态获取到颜色了
     
    int color = COLORS[id % COLORS.length];
     
     
    设置背景
     

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
    setBackground(states);
    else
    setBackgroundDrawable(states);
     
     
    Tip7: 关于Build

    apply plugin: 'com.android.application'

    def getGitVersion() {
    try {
    return 'git rev-parse --short HEAD'.execute().text.trim()
    } catch (Throwable th) {
    return "";
    }
    }

    android {
    compileSdkVersion 23
    buildToolsVersion buildToolsVer
    useLibrary 'org.apache.http.legacy'

    defaultConfig {
    minSdkVersion 9
    targetSdkVersion 23
    buildConfigField "String", "GIT_REVISION", ""${getGitVersion()}""
    buildConfigField "String", "BUILD_DATE", ""${new Date().toLocaleString()}"";
    }

    signingConfigs {
    debug { storeFile file("debug.keystore") }

    release {
    storeFile file('release.keystore')
    storePassword 'thisiskeystorepassword'
    keyAlias 'nim_demo'
    keyPassword 'thisiskeypassword'
    }
    }

    buildTypes {
    debug {
    signingConfig signingConfigs.debug
    manifestPlaceholders = [ AMAP_KEY:"09fd4efd3e28e9bf1f449ecec7d34bfe" ]
    }

    release {
    minifyEnabled true
    zipAlignEnabled true
    proguardFile('proguard.cfg')
    signingConfig signingConfigs.release
    manifestPlaceholders = [ AMAP_KEY:"ee20324fba1c7f4ad7a4a207e7f08e8d" ]
    }
    }
    sourceSets {
    main {
    manifest.srcFile 'AndroidManifest.xml'
    java.srcDirs = ['src']
    resources.srcDirs = ['src']
    aidl.srcDirs = ['src']
    renderscript.srcDirs = ['src']
    res.srcDirs = ['res', 'res-avchat', 'res-chatroom']
    assets.srcDirs = ['assets']
    jniLibs.srcDirs = ['libs', 'libs-sdk']

    }

    }

    lintOptions {
    checkReleaseBuilds false
    abortOnError false
    }
    dexOptions {
    incremental true
    preDexLibraries false
    jumboMode true
    }
    packagingOptions {
    exclude 'META-INF/LICENSE.txt'
    exclude 'META-INF/NOTICE.txt'
    }

    }

    dependencies {
    compile fileTree(dir: 'libs', include: '*.jar', exclude: ['android-support-*.jar'])
    compile project(path: ':uikit')
    }
     

    在Activity中引用build中定义的变量:
     
    在AndroidMainfest.xml中引用配置的key:
     
     
     
     
  • 相关阅读:
    根据pandas和matplotlib制作简单的图表
    python-pandas 描述和汇总统计表
    linux json的使用
    zend studio10.5 + apache2.2 + php5.2.8 + xdebug2.3
    form表单中name和id区别
    浏览器中访问php页面没法正常显示
    zend studio
    ajax调试 No 'Access-Control-Allow-Origin' header is present on the requested resource
    火狐下input密码框自动填充值和php传数组给js的问题
    mysql 联合 count
  • 原文地址:https://www.cnblogs.com/spring87/p/5799062.html
Copyright © 2011-2022 走看看