小功能实现记录2

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签名。




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时,就可以直接显示原来修改后的样子。
 注意:当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文件是个 <selector> </selector>,不好意思,根据其中 <item> </item>的种类数量,你的每种 <item> </item>需要再double一份
最后再这样 xxxActivity.java
@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); 


























  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值