Android code wiki

简介:   Android code wiki Tip1: 类的全局静态变量的使用,这样可以静态变量只分配一次内存,可以不通过类的对象也就是可以通过类名直接使用该变量。(使用场景:Request_Code ,Result_Code,Log Tag,权限名字,Activity之间传递参数Name e...

 

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:
 
 
 
 

 

目录
相关文章
|
7月前
|
JSON 编译器 开发工具
VS Code阅读Android源码
VS Code阅读Android源码
541 1
|
Android开发
AS插件-Android Parcelable code generator.
AS插件-Android Parcelable code generator.
182 0
|
存储 缓存 JSON
Code For Better 谷歌开发者之声——Android 中的 Volley 库
Volley是一个HTTP 库,它使 Android 应用程序的网络变得非常简单和快速。它由 Google 开发并在 2013 年 Google I/O 期间推出。它的开发是因为 Android SDK 中缺少能够在不影响用户体验的情况下工作的网络类。尽管 Volley 是 Android 开源项目 (AOSP) 的一部分,但 Google 在 2017 年 1 月宣布 Volley 将迁移到一个独立的库。它管理网络请求的处理和缓存,并节省开发人员一次又一次编写相同的网络调用/缓存代码的宝贵时间。Volley不适合大型下载或流式操作,因为 Volley 在解析期间将所有响应保存在内存中。
145 0
|
Android开发
1--debug时安卓源码不一致问题--Source code does not match the bytecode
AS--debug时:Source code does not match the bytecode 解决方案:保持模拟器与编译版本一致,即: 编译版本与运行版本一致
3598 0
|
Android开发
Android项目实战(十九):Android Studio 优秀插件: Parcelable Code Generator
原文:Android项目实战(十九):Android Studio 优秀插件: Parcelable Code Generator Android Studio 优秀插件系列:                       Android Studio 优秀插件(一):GsonFormat    ...
940 0
|
Android开发
simple Android EventBus code
import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.
717 0
|
存储 Web App开发 Java
android file 存储 html 导致 pre[code=java] 不换行
     android file 存储 html  导致 pre[code=java] 不换行    显示 html 如图  代码 如图  原因: 在写文件的时候 在写入文件就直接写成了 一行,所以 在 高亮的时候是不能够换行了,所以 正确的方式应该是 在写入文件的时候让他换行,或者 ,像我一样,投机取巧,存在db 中,样式是不会改变的 。
778 0