1.length,length()和size()
数组有length属性,没有length()方法;字符串有length()方法;list以及map集合等有size()方法
int[] a = new int[] { 1, 1 };
System.out.println("a.length-->" + a.length);
String str = "aaa";
System.out.println("str.length()-->" + str.length());
List list = new ArrayList();
System.out.println("list.size()-->" + list.size());
Map map = new HashMap();
System.out.println("map.size()-->" + map.size());
2.获得当前进程名
public String getProcessName() {
ActivityManager am = (ActivityManager) getApplicationContext()
.getSystemService(Context.ACTIVITY_SERVICE);
int myPid = android.os.Process.myPid();
for (ActivityManager.RunningAppProcessInfo runningPro : am
.getRunningAppProcesses()) {
if (runningPro.pid == myPid) {
processName = runningPro.processName;
}
}
return processName;
}
3.ListView的scrollbar的位置
将滚动条设置到左侧
getListView().setVerticalScrollbarPosition(View.SCROLL_INDICATOR_LEFT);
也可以设置其他位置
4.防止重复点击
public class NoDoubleClickUtils {
private static long lastClickTime;
private final static int SPACE_TIME = 500;
public static void initLastClickTime() {
lastClickTime = 0;
}
public synchronized static boolean isDoubleClick() {
long currentTime = System.currentTimeMillis();
boolean isClick2;
if (currentTime - lastClickTime > SPACE_TIME) {
isClick2 = false;
} else {
isClick2 = true;
}
lastClickTime = currentTime;
return isClick2;
}
}
使用方法:
private View.OnClickListener logListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
if (!NoDoubleClickUtils.isDoubleClick()) {
EventBus.getDefault().post(new RefreshEvent(RefreshEvent.RefreshType.TYPE_LAND_ORDER_LOG, view.getTag()));
}
}
};
5.如何重新设置一个View的LayoutParams
MarginLayoutParams params = (MarginLayoutParams) button.getLayoutParams();
params.width += 100;
params.leftMargin += 100;
button.requestLayout();
// 或者 button.setLayoutParams(params);
6.service的隐式启动和显式启动
隐式启动
<service android:name=".service">
<intent-filer>
<action android:name="com.android.service"/>
<intent-filer>
</service>
final Intent serviceIntent=new Intent();
serviceIntent.setAction("com.android.service");
显示启动
final Intent serviceIntent=new Intent(this,service.class);
startService(serviceIntent);
如果在同一个包中。两者都可以用。在不同包时。只能用隐式启动
7.防止Toast多次点击多次显示
public class MainActivity extends Activity {
Toast toast;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (toast != null) {
toast.setText("click");
toast.setDuration(Toast.LENGTH_LONG);
toast.show();
} else {
toast = Toast.makeText(getApplicationContext(), "njj",
Toast.LENGTH_LONG);
toast.show();
}
}
});
}
}
8.key如何判断长按
if((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
<span style="white-space:pre"> </span>android.util.Log.i("NieJianJian_Kodiak_Test", "KeyEvent.KEYCODE_PTT -> down -> longPress");
<span style="white-space:pre"> </span>mPTTLongPressed = true;
}
按键按下,会有一个down,然后500ms后,再发一次down,然后就会进入上面的判断中,也就是说只要走到了上面的内容,就是长按了。
还有就是判断repeatcount的值
if(event.getRepeatCount() == 0) {
// 。。。。
}
down按下,500ms会发送带flags的长按的down,然后每隔50ms发送一次down。
第一次repeatcount = 0;当长按的down来的时候,repeatcount = 1;之后的每一个down的数值都+1;可以用repeatcount是否等于0来判断是单击还是长按。
9.在RelativeLayout中有一个button按钮,请确定该按钮相对于手机屏幕的位置坐标
View view = findViewById(R.id.button1);
// 数组长度必须为2
int [] locations = new int[2];
view.getLocationOnScreen(locations);
int x = locations[0];
int y = locations[1];
10.如何动态改变RelativeLayout中按钮的布局。
首先应该获得按钮对象,然后使用LayoutParams.addRule方法设置相应的属性,(下面的代码将按钮从左上角的位置动态设置到了屏幕中心的位置)
Button button = relativeLayout.findViewById(R.id.button1);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
ViewGroup.LayoutParams. WRAP_CONTENT,
ViewGroup.LayoutParams. WRAP_CONTENT);
// 设置android:layout_centerInParent属性
layoutParams.addRule(RelativeLayout. CENTER_IN_PARENT,
RelativeLayout. TRUE);
// 修改按钮的android:layout_centerInParent属性的值
button.setLayoutParams(layoutParams);
11.将布局存成图像
(1).如何将当前界面的可视化组件以同样的相对位置和大小保存在png图像文件中。(截取当前界面的组件和保存成png图像文件,首先要调用view.setDrawingCacheEnabled方法打开图像缓存,然后使用view.getDrawingCache方法获取View的Bitmap对象,保存成png图像使用Bitmap.compress方法即可)
View view = getLayoutInflater().inflate(R.layout.main, null);
// 打开图像缓存
View.setDrawingCacheEnabled(true);
// 必须要调用measure和layout方法才能成功保存可视组件的截图到 png图像文件
// 测量View大小
view.measure(MeasureSpec. makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec. makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
// 发送位置和尺寸到View及其所有的子View
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
try {
// 获取可视组件的截图
Bitmap bitmap = view.getDrawingCache();
// 将截图保存在SD卡根目录的test.png图像文件中
FileOutputStream fos = new FileOutputStream("/sdcard/test.png" );
// 将Bitmap对象中的图像数据压缩成 png格式的图像数据,并将这些数据保 存在test.png文件中
bitmap.compress(CompressFormat. PNG, 100, fos);
// 关闭文件输出流
fos.close();
} catch (Exception e) {
// TODO: handle exception
}
12.如何将Android应用程序窗口的背景色设置为渐变色
// 设置从上向下的渐变色,上方是红色,下方是黄色
GradientDrawable gradientDrabable = new GradientDrawable(
Orientation.TOP_BOTTOM,new int[]
{Color.RED, Color.YELOW});
// 设置当前窗口的渐变背景色
getWindow().setBackgroundDrawable(gradientDrawable);
13.如何在EditText中显示提示文本,在提示文本后面可以输入文本?
方法一:在EditText内部显示提示文本一般可以通过android:drawableLeft属性来实现。首先要做一个带有提示文本的图像,并通过android:drawableLeft属性指定该图像文件的资源ID。但这种方法不灵活,如果想要更换提示文本,就需要换图像。
方法二:通过android:paddingLeft属性和Canvas来实现,这种方法可以更灵活的处理提示文本
可以直接在EditText中绘制提示文本,首先编写一个继承自EditText的类,并覆盖onDraw方法,在该方法中绘制提示文本,代码如下:
@Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setTextSize(18);
paint.setColor(Color. GRAY);
// 绘制提示文本,
canvas.drawText( "输入提示文本:" , 2, getHeight() / 2 + 5, paint);
super.onDraw(canvas);
}
14.如何为ListView加上快速滑块,怎么修改快速滑块的图案?
使用布局文件需要将android:fastScrollEnabled属性设置为true,使用Java带am需要调用ListView.setFastScrollEnabled(true)方法。
ListView组件并没有提供修改快速滑块图像的API,因此不能直接修改快速滑块的图像,但可以通过反射技术修改快速滑块图像,代码如下:
// FastScroller.mThumbDrawable变量保存了快速滑块图像,首先通过AbsListView.mFastScroller变量
// 获取FastScroller对象
Field field = AbsListView.class.getDeclaredField("mFastScroller" );
field.setAccessible( true);
Object obj = field.get( listView);
// 获取FastScroller。mThumbDrawable变量的Field对象
field = field.getType().getDeclaredField("mThumbDrawable" );
field.setAccessible( true);
// 获取FastScroller.mThumbDrawable变量的值
Drawable drawable = (Drawable) field.get(obj);
// 装载新的快速滑块对象
drawable = getResources().getDrawable(R.drawable.image);
// 重新设置快速滑块的图像
field.set(obj, drawable);
15.TextView中显示图像
1).使用<img>标签在TextView组件中显示图像
CharSequence charSequence = Html.fromHtml(Html, new ImageGetter() {
@Override
public Drawable getDrawable(String source) {
// 装载图像资源
Drawable drawable = getResources().getDrawable(
getResourceId(source));
// 设置要显示图形的大小(按原大小显示)
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight());
return drawable;
}
}, null);
textview.setText(charSequence);
2).使用ImageSpan对象在TextView组件中显示
// 根据资源ID获得资源图像的Bitmap
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable. ic_launcher);
// 根据Bitmap对象创建ImageSpan对象
ImageSpan imageSpan = new ImageSpan( this, bitmap);
// 创建一个SpannableString对象,以便插入用ImageSpan对象封装的图像
SpannableString spannableString = new SpannableString("icon");
// 用ImageSpan对象替换icon
spannableString.setSpan(imageSpan, 0, 4,
Spannable. SPAN_EXCLUSIVE_EXCLUSIVE);
// 将图像显示在TextView组件上
textView.setText(spannableString);
16.Android启动应用市场
如果手机上没有应用市场,运行时会报错,所以,可以用try-catch,在catch中执行一些操作什么的,就可以避免crash。
启动应用市场
private void startStore1() {
try{
Intent intent = new Intent("android.intent.action.MAIN");
intent.addCategory("android.intent.category.APP_MARKET");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
} catch (Exception e){
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.bidit.cn/"));
startActivity(intent);
}
}
应用市场在定位应用
传入包名就可以了
private void startStore2() {
try{
String str = "market://details?id=" + getPackageName();
Intent intent = new Intent("android.intent.action.VIEW");
intent.setData(Uri.parse(str));
startActivity(intent);
} catch (Exception e){
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.bidit.cn/"));
startActivity(intent);
}
}
17.如何判断应用是否在前台
package com.os.bdauction.application;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import com.os.bdauction.utils.AppLifeCycleAware;
import com.os.soft.rad.app.BaseApplication;
public class BDApplication extends BaseApplication {
private static Context mAppContext;
/* 可见的activity组件数量 */
private static int visibleComponentCount = 0;
/**
* 应用是否在前台
*/
public static boolean isForeground(){
return visibleComponentCount > 0;
}
@Override
public void onCreate() {
super.onCreate();
mAppContext = this;
registerActivityLifecycleCallbacks(callbacks);
}
public static Context getApplication(){
return mAppContext;
}
@Override
public void onTerminate() {
unregisterActivityLifecycleCallbacks(callbacks);
super.onTerminate();
}
/*应用生命周期监听*/
private ActivityLifecycleCallbacks callbacks = new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(Activity activity) {
visibleComponentCount += 1;
}
@Override
public void onActivityResumed(Activity activity) {}
@Override
public void onActivityPaused(Activity activity) { }
@Override
public void onActivityStopped(Activity activity) {
visibleComponentCount -= 1;
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
};
}
18.scrollview嵌套textview上方显示不全下方有空白
造成这个问题的原因是因为textview android:layout_gravity="center"导致,当然我是知道原因的,如果想要在这个前提下使textview充满scrollview,只需在scrollview中添加语句android:fillViewport="true"
19.启动应用白屏时间过长的问题
修改style.xml主题
<style name="AppTheme" parent="android:Theme.Holo.Light.NoActionBar">
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsTranslucent">true</item>
</style>
其中加入了两个属性,windowIsTranslucent和windowNoTitle,将这两个属性设置为true,就可以让程序在初始化的时候窗口是透明的,初始化结束后程序主界面才能显示出来,从而也就完全看不到白屏界面了
20.应用查看签名的方法
1) 将apk修改后缀为 .rar文件后解压;
2) 进入解压后的META-INF目录,该目录下会存在文件CERT.RSA
3) 在该目录下打开cmd,输入命令 :keytool -printcert -file CERT.RSA
这里将会显示出MD5和SHA1签名。
2) 进入解压后的META-INF目录,该目录下会存在文件CERT.RSA
3) 在该目录下打开cmd,输入命令 :keytool -printcert -file CERT.RSA
这里将会显示出MD5和SHA1签名。
21.Activity中切换Layout布局
R.layout.main是个布局文件即控件都是如何摆放如何显示的,setContentView就是设置一个Activity的显示界面,这句话就是设置这个这句话所再的Activity采用R.layout下的main布局文件进行布局。
使用setContentView可以在Activity中动态切换显示的View,这样,不需要多个Activity就可以显示不同的界面,因此不再需要在Activity间传送数据,变量可以直接引用。但是,在android SDK给我们建的默认的Hello World程序中,调用的是setContentView(int layoutResID)方法,如果使用该方法切换view,在切换后再切换回,无法显示切换前修改后的样子,也就是说,相当于重新显示一个view,并非是把原来的view隐藏后再显示。其实setContentView是个多态方法,我们可以先用LayoutInflater把布局xml文件引入成View对象,再通过setContentView(View view)方法来切换视图。因为所有对View的修改都保存在View对象里,所以,当切换回原来的view时,就可以直接显示原来修改后的样子。
使用setContentView可以在Activity中动态切换显示的View,这样,不需要多个Activity就可以显示不同的界面,因此不再需要在Activity间传送数据,变量可以直接引用。但是,在android SDK给我们建的默认的Hello World程序中,调用的是setContentView(int layoutResID)方法,如果使用该方法切换view,在切换后再切换回,无法显示切换前修改后的样子,也就是说,相当于重新显示一个view,并非是把原来的view隐藏后再显示。其实setContentView是个多态方法,我们可以先用LayoutInflater把布局xml文件引入成View对象,再通过setContentView(View view)方法来切换视图。因为所有对View的修改都保存在View对象里,所以,当切换回原来的view时,就可以直接显示原来修改后的样子。
注意:当activity 调用 setContentView() 时,android 才会去绘制 layout 上的各个元素,并为其分配内存。只有 分配了内存以后,才能继续执行 ,findViewById(); 才能得到引用,不然得到空引用。空引用意味着,后面使用相应变量时就会发生访问的对象不存在的问题。而且当Activity重新setContentView()以后,那些之前绘制的控件,内存都被灭掉了。所以,若是通过setContentView来达到画面切换目的的,要注意重新绘制以后重新取得引用。
22.获取渠道名称
public class Channels {
private static final String CHANNEL = "META-INF/channel";
private static String channel = "";
public static String getChannel() {
return getChannel(BDApplication.getApplication());
}
public static String getChannel(Context context) {
if (TextUtils.isEmpty(channel)) {
channel = getChannelInner(context);
}
return channel;
}
public static String getChannelInner(Context context) {
ApplicationInfo appInfo = context.getApplicationInfo();
String sourceDir = appInfo.sourceDir;
String ret = "";
ZipFile zipfile = null;
try {
zipfile = new ZipFile(sourceDir);
Enumeration<?> entries = zipfile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = ((ZipEntry) entries.nextElement());
String entryName = entry.getName();
if (entryName.startsWith(CHANNEL)) {
ret = entryName;
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (zipfile != null) {
try {
zipfile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
String[] split = ret.split("_");
if (split.length >= 2) {
return split[1];
} else {
return "test";
}
}
}
23.时间格式化
public class BDDateFormat {
/**
* 格式化日期
*/
public static CharSequence formatDate(long time) {
return DateFormat.format("yyyy-MM-dd", time);
}
public static CharSequence formatTime(long time) {
return DateFormat.format("yyyy-MM-dd HH:mm:ss", time);
}
public static CharSequence formatTimeWithoutYearField(long timeStamp) {
return DateFormat.format("MM月dd日 HH:mm:ss", timeStamp);
}
public static CharSequence formatTimeWithoutYearField2(long timeStamp) {
return DateFormat.format("MM月dd日 HH:mm:ss", timeStamp);
}
public static CharSequence formatTimeWithoutYearSecondField(long timeStamp) {
return DateFormat.format("MM月dd日 HH:mm", timeStamp);
}
public static CharSequence formatTimeWithoutYearSecondField1(long timeStamp) {
return DateFormat.format("yyyyMMddHH", timeStamp);
}
}
24.动态获取view宽高和动态设置
boolean measureFinish;
private void setViewHeight() {
mPayPopContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
mPayPopContent.postDelayed(new Runnable() {
@Override
public void run() {
if (mPayPopContent.getHeight() != 0 && !measureFinish) {
RelativeLayout.LayoutParams layoutParams = (LayoutParams) mLoadingView.getLayoutParams();
layoutParams.height = mPayPopContent.getHeight();
mLoadingView.setLayoutParams(layoutParams);
measureFinish = true;
return;
}
}
}, 100);
}
});
}
25.ScrollView中的ListView值显示一条数据
动态计算你一下大小
public void fixListViewHeight(ListView listView) {
// 如果没有设置数据适配器,则ListView没有子项,返回。
ListAdapter listAdapter = listView.getAdapter();
int totalHeight = 0;
if (listAdapter == null) {
return;
}
for (int index = 0, len = listAdapter.getCount(); index < len; index++) {
View listViewItem = listAdapter.getView(index, null, listView);
// 计算子项View 的宽高
listViewItem.measure(0, 0);
// 计算所有子项的高度和
totalHeight += listViewItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
// listView.getDividerHeight()获取子项间分隔符的高度
// params.height设置ListView完全显示需要的高度
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
会自动跳到listview开始的位置,为了避免这个效果,让listview之外的布局获得焦点、
android:focusableInTouchMode="true"
27.dialog显示全屏
方法一:代码实现
首先继承Dialog,然后在构造方法在添加
super(context, Android.R.style.Theme);
setOwnerActivity((Activity)context);
方法二:XML实现
<style name="PopupDialog">
<item name="android:windowNoTitle">true</item>
<item name="android:windowFullscreen">true</item>
</style>
这个style不能有继承,否则无效
然后代码中写
Dialog dialog = new Dialog(this, R.style.PopupDialog);
dialog.setContentView(R.layout.main);
dialog.show();
28.ListView复用,乱跳的解决
其实更多的是记录解决的思路
既然数据乱跳,就每次都初始化数据
1).场景:litview每一个item都有一个倒计时,都会创建一个subScribe对象,但是关闭掉listview所在的activity之后,发现log其实一直在打印
解决方法:在listview所在的activity中,创建一个static的list,泛型存放的是subScribe对象,在activity执行销毁的onDestiry中,将list的所有对象遍历出来,依次进行解绑。
2).场景:ListView的每一个item都有一个textSwitcher,里面有一个textview,显示当前的领先用户,当被别人顶掉之后,会调用textSwitcher.setText(),这个方法一执行,就会执行动画,实现一个轮播的效果。所以,我在hodler中定义两个一个tempStr,来记录每一个item的当前的内容,用来和新的比较,来决定是否要轮换。
但是,问题来了如果我手机当前可见的的最大item条数为5条,根据holder的复用的原则,我只会生成5个holder对象,如果我有10条数据,那么,用的也是这5个holder,所以导致10个item用了5个item的holder中的tempStr,这样,就会导致,当复用的时候,当前的领先用户,匹配的是别的item的值,这样就会导致数据乱跳,以及频繁执行轮播动画。
解决方法:在Listview的Activity中创建一个map<Integer,String>,然后,key值就是position,因为是唯一的,这样,就可以独立每一条的数据,有几条item,map就会有几条,就不会因为复用导致这么多问题了
29.drawble类型的selector使用color
当我们@drawable来使用一个selector的时候,item中是不能直接android:color="'的,就好比@color中不能使用android:drawable=""一样,会报一个类型转换异常的错误。
我们可以给item设置一个shape。这样就可以直接设置颜色值了
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false">
<shape android:shape="rectangle">
<solid android:color="#FAC3C3"/>
</shape>
</item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="#C62E2E"/>
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="@color/text_brown"/>
</shape>
</item>
</selector>
30.List和数组的转换
数组转List
1).方法一
String[] userid = {"aa","bb","cc"};
List<String> userList = new ArrayList<String>();
Collections.addAll(userList, userid);
2).方法二
String[] userid = {"aa","bb","cc"};
List<String> userList = Arrays.asList(userid);
Arrays.asList返回一个受指定数组支持的固定大小的列表,所以不能做add和remove等操作,按照如下操作就可以了
List list = new ArrayList(Arrays.asList(userid));
3).方法三
String[] userid = {"aa","bb","cc"};
List<String> userList = new ArrayList<String>(userid.length);
for(String uid: userid){
userList.add(uid);
}
List转数组
1).方法一
List<String> strList = new ArrayList<String>();
strList.add("aa");
strList.add("bb");
Object[] objs = strList.toArray();
如果想变成String可以强转:
String[] strs = (String[]) strList.toArray(new String[0]);
也可以指定大小:
String[] strs = strList.toArray(new String[strList.size()]);
2).方法二
List<String> strList = new ArrayList<String>();
strList.add("aa");
strList.add("bb");
String[] strs = new String[strList.size()];
31.运行时权限的申请
1.单个权限申请
在操作的地方执行以下代码
/*ContextCompat.checkSelfPermission() 检查是否已经授权*/
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
// context, 权限名, 请求code
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CALL_PHONE}, 1);
} else {
// 执行相关操作
}
Activity重写 onRequestPermissionResult方法
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 执行相关操作
} else {
// 因为没有权限无法操作的提示或者处理
}
break;
}
}
2.多个权限同时申请
String[] mPermissions = new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.READ_PHONE_STATE};
List<String> mPermissionList = new ArrayList<>();
private void applyPermission() {
mPermissionList.clear();
for (String permission : mPermissions) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
mPermissionList.add(permission);
}
}
if (!mPermissionList.isEmpty()) {
String[] permissions = mPermissionList.toArray(new String[mPermissionList.size()]);
ActivityCompat.requestPermissions(this, permissions, 1);
} else {
// 执行相关操作
loginHandle();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1:
boolean shouldApply = false;
boolean shouldRequestPermission = true;
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
// shouldShowRequestPermissionRationale {true : 拒绝 ; false : 拒绝后不在询问}
shouldApply = true;
if (shouldRequestPermission) {
shouldRequestPermission =
ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[i]);
}
}
}
if (shouldApply) {
showPermissionDialog(shouldRequestPermission);
}
/*if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 执行相关操作
loginHandle();
} else {
// 因为没有权限无法操作的提示或者处理
// shouldPermission为true表示拒绝,false表示拒绝并不在询问
boolean shouldPermission = ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[0]);
showPermissionDialog(shouldPermission);
}
break;*/
}
}
通过shouldShowRequestPermissionRationable()的返回值,来判断某权限只是简单拒绝了,还是不在询问。如果返回true,表示拒绝了该权限。如果返回false,表示选择了不在询问,这样就应该调用相关逻辑,来引导用户去设置中开启权限。
TextView mConfirm;
TextView mCancel;
private void showPermissionDialog(final boolean shouldPermission) {
LayoutInflater inflater = LayoutInflater
.from(this);
View view = inflater.inflate(R.layout.permission_view, null);
final Dialog dialog = new Dialog(this);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(view);
dialog.setCancelable(false);
dialog.setCanceledOnTouchOutside(false);
dialog.show();
mConfirm = (TextView) view.findViewById(R.id.confirm);
mCancel = (TextView) view.findViewById(R.id.cancel);
mConfirm.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
if (shouldPermission) {
applyPermission();
} else {
Uri packageURI = Uri.parse("package:" + "***.***.***"); // ***代表包名
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageURI);
startActivity(intent);
}
}
});
mCancel.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
}
32.TaskStackBuilder的作用
调起Notification,点击通知栏的notification,出发pengdingintent之后,跳转到相应的界面,此时点击返回键,是回到系统桌面,如果我想回到指定位置,比如应用的主页面,就是用TaskStackBuilder来实现。
33.代码更新TextView的颜色方法
mEditText.setTextColor(getResources().getColor(android.R.color.holo_red_dark));
mEditText.setTextColor(getResources().getColorStateList(android.R.color.holo_green_dark));
mEditText.setTextColor(Color.parseColor("#0000FF"));
mEditText.setTextColor(Color.RED);
mEditText.setTextColor(Color.rgb(255, 0, 0));
mEditText.setTextColor(0xFF00FF00);
34.跑马灯
<TextView
android:id="@+id/horse_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:focusable="true"
android:focusableInTouchMode="true"
android:marqueeRepeatLimit="marquee_forever"
android:maxLines="1"
android:text="***********************************"/>
mTextView.setHorizontallyScrolling(true);
也可以在xml中设置HorizontallyScrolling属性。
保证跑马灯运行的必要属性:
android:ellipsize="marquee"//文字显示不完全,以什么方式显示(这里就以滚动的行形式)
android:focusable="true"//获得焦点
android:focusableInTouchMode="true"//获得触摸焦点
android:marqueeRepeatLimit="marquee_forever"//滚动模式
android:scrollHorizontally="true"//横向滚动
android:singleLine="true"//以单行文本显示
而且显示的文字,必须要超过给定的宽度才可以。
如果页面view太多,textview可能就无法获得焦点,这样就需要专门处理下,
/**
*自定义TextView 重写isFocused()函数,让他放回true也就是一直获取了
*焦点效果自然也就出来了,如果这都不能解决那肯定就不是焦点问题了。
*那就要找到问题,在想办法解决
*/
public class MarqueTextView extends TextView {
public MarqueTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public MarqueTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MarqueTextView(Context context) {
super(context);
}
@Override
public boolean isFocused() {
return true;
}
}
maxLines不行,可能需要换成android:singleLines="true"才可以。
问题:如果有videoview存在,视频播放时,会抢占焦点,跑马灯停止,解决办法,重写onFocusChanged方法就可以,方法中什么也不用写
@Override
protected void onFocusChanged(boolean focused, int direction,
Rect previouslyFocusedRect) {
}
35.获取即将显示的文字的宽度
public void getSpaceWidth2() {
String str = SPACE;
int iRet = 0;
if (str != null && str.length() > 0) {
int len = str.length();
float[] widths = new float[len];
mTextView.getPaint().getTextWidths(str, widths);
for (int j = 0; j < len; j++) {
iRet += (int) Math.ceil(widths[j]);
}
}
Log.i("niejianjian"," -> getSpaceWidth2 -> " + iRet);
}
public void getSpaceWidth() {
Rect rect = new Rect();
Paint paint = mTextView.getPaint();
paint.getTextBounds(SPACE, 0, SPACE.length(), rect);
int mWidth = rect.width();
Log.i("niejianjian", " -> getSpaceWidth -> " + rect.width());
}
36. ?attr/*** 使用
color.xml中定义两个颜色
<color name="color_a">#ffffff</color>
<color name="color_a_night">#000000</color>
然后attr.xml中定义一个值
<attr name="colorA" format="color"/>
然后style.xml中定义两个主题
<style name="Theme.A">
<item name="colorA">@color/color_a</item>
</style>
<style name="Theme.A.Night">
<item name="colorA">@color/color_a_night</item>
</style>
使用的时候这样使用activity_xxx.xml
<View
android:id="@+id/xxx"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorA"/>
如果此处你设置的background是一个drawable文件,你需要创建两个drawable文件(一个日间文件,一个带_night的夜间文件)。如果你>的这个drawable文件是个
最后再这样 xxxActivity.java
<selector> </selector>
,不好意思,根据其中
<item> </item>
的种类数量,你的每种
<item> </item>
需要再double一份
@Override
protected void onCreate(Bundle savedInstanceState) {
...
if(!isNightMode()) {
setTheme(R.style.Theme_A);
} else {
setTheme(R.style.Theme_A_Night);
}
setContentView(R.layout.activity_xxx);
...
}
最终会根据style的不同,会调用不同的值。
如果在代码中设置值,可以这样
int[] attrs = { R.attr.colorA };
TypedArray ta = context.getTheme().obtainStyledAttributes(attrs);
int color = ta.getColor(ArrayUtils.indexOf(attrs, R.attr.colorA), 0);
ta.recycle();
textView.setTextColor(color);
37.android震动动画的实现
ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f).setDuration(1000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
Random random = new Random();
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mImageView.setTranslationX((random.nextFloat() - 0.5f) * mImageView.getWidth() * 0.02f);
mImageView.setTranslationY((random.nextFloat() - 0.5f) * mImageView.getHeight() * 0.02f);
}
});
animator.start();
38.android 5.0隐式启动bug
Intent intent = new Intent();
intent.setAction("com.example.user.firstapp.FIRST_SERVICE");
bindService(intent,coon,Service.BIND_AUTO_CREATE);
不管是bindService还是startService,都是存在问题的,会报错,信息是:Service Intent must be explicit
解决方法,第一种是将隐式启动改为显示启动,第二种是将隐式启动转化为显示启动,先定义一个函数:
/***
* Android L (lollipop, API 21) introduced a new problem when trying to invoke implicit intent,
* "java.lang.IllegalArgumentException: Service Intent must be explicit"
*
* If you are using an implicit intent, and know only 1 target would answer this intent,
* This method will help you turn the implicit intent into the explicit form.
*
* Inspired from SO answer: http://stackoverflow.com/a/26318757/1446466
* @param context
* @param implicitIntent - The original implicit intent
* @return Explicit Intent created from the implicit original intent
*/
public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {
// Retrieve all services that can match the given intent
PackageManager pm = context.getPackageManager();
List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
// Make sure only one match was found
if (resolveInfo == null || resolveInfo.size() != 1) {
return null;
}
// Get component info and create ComponentName
ResolveInfo serviceInfo = resolveInfo.get(0);
String packageName = serviceInfo.serviceInfo.packageName;
String className = serviceInfo.serviceInfo.name;
ComponentName component = new ComponentName(packageName, className);
// Create a new intent. Use the old one for extras and such reuse
Intent explicitIntent = new Intent(implicitIntent);
// Set the component to be explicit
explicitIntent.setComponent(component);
return explicitIntent;
}
调用方法如下:
final Intent intent = new Intent();
intent.setAction("com.example.user.firstapp.FIRST_SERVICE");
final Intent eintent = new Intent(createExplicitFromImplicitIntent(this,intent));
bindService(eintent,conn, Service.BIND_AUTO_CREATE);