0%

如果你的TextView在ListView/GridView中,会发现设置了android:ellipsize=”marquee”后没有效果,这是因为TextView需要在获取焦点时才会滚动,而如果加了android:focusable=”true”,GridView的焦点被TextView抢走,无法响应点击事件。解决方法:自定义一个View继承系统的TextView,覆盖isFocused()方法,直接返回true,这是因为系统会调用isFocused()方法判断TextView是否已经取到焦点,如果没取到,使用默认的ellipsize=”start” 注:item多时,会明显感觉比不滚动要卡很多,不建议使用,改设计吧

Android Studio现在生成的配置文件还不会自动添加so库,需要在build.gradle里手动加几行代码:

android {
    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }

把jniLibs.srcDirs = [‘libs’] 放到android.sourceSets.main下,原有的不要删

Android support v4包里已经包含了生成圆角(圆形)的方法,太贴心了.

       Bitmap src=BitmapFactory.decodeResource(getResources(),R.drawable.temp_avatar);
        RoundedBitmapDrawable roundedBitmapDrawable =
                RoundedBitmapDrawableFactory.create(getResources(),src);
        //设置圆角半径
        roundedBitmapDrawable.setCornerRadius(Math.max(src.getWidth(), src.getHeight()) / 2.0f);
        imageViewAvatar.setImageDrawable(roundedBitmapDrawable);

当圆角半径为宽高中最大值的一半时,生成的就是圆形图片.

默认情况下,在有硬件menu键的手机上,不会显示menu图标(右上角三个点),如果功能依赖这个菜单,可能在对某些用户来说就有些隐晦了,他们可能无法找到这些功能。 要强制系统显示menu图标,可以用反射的方法,把ViewConfiguration对象的sHasPermanentMenuKey属性设为false,让系统以为没有硬件菜单键。

       try {
            ViewConfiguration config = ViewConfiguration.get(this);
            Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
            if (menuKeyField != null) {
                menuKeyField.setAccessible(true);
                menuKeyField.setBoolean(config, false);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

下面这张Fragment生命周期图大家应该看得很多了: 1354170699_6619 但最近在写PageManager(管理页面跳转),发现切换页面时,之前的页面走完onDestoryView就直接onDestory了,回来又重新onCreate,如果用hide和show的方式,都不走生命周期,看了ApiDemo代码,发现原因,整理一下. 切换Fragment有两种方式,一种是add新的,并把旧的hide,另一种是replace. 旧的Fragment为Fragment1,新的是Fragment2,忽略非关键生命周期。 使用add方法切换时: 载入Fragment1 Fragment1 onCreate Fragment1 onCreateView Fragment1 onStart Fragment1 onResume 用以下代码切到Fragment2:

        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.hide(Fragment1);
        ft.add(R.id.simple_fragment, Fragment2);
        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
        ft.commit();

Fragment1不走任何生命周期,但会调onHiddenChanged方法 Fragment2 onCreate Fragment2 onCreateView Fragment2 onStart Fragment2 onResume 回到Fragment1,Remove Fragment2:

        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.remove(Fragment2);
        ft.show(Fragment1);
        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
        ft.commit();

Fragment1还是不走任何生命周期,调onHiddenChanged方法 Fragment2 onPause Fragment2 onStop Fragment2 onDestoryView Fragment2 onDestory 用这种方法切换,Fragment在隐藏时并不会走onDestoryView,所以显示时也不会走onCreateView,所有View都一直保存在内存中。 用replace方法: 载入Fragment1生命周期与上面相同: Fragment1 onCreate Fragment1 onCreateView Fragment1 onStart Fragment1 onResume 切到Fragment2:

        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.replace(R.id.simple_fragment, Fragment2);
        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
        ft.commit();

这次的Fragment1走生命周期了 Fragment1 onPause Fragment1 onStop Fragment1 onDestoryView Fragment1 onDestory Fragment2 onCreate Fragment2 onCreateView Fragment2 onStart Fragment2 onResume 真实打印出来可能是Fragment1和Fragment2混在一起的,可以看到,Fragment1走了onDestory,被完全回收了! 再切回到Fragment1

        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.replace(R.id.simple_fragment, Fragment1);
        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
        ft.commit();

Fragment1 onCreate Fragment1 onCreateView Fragment1 onStart Fragment1 onResume Fragment2 onPause Fragment2 onStop Fragment2 onDestoryView Fragment2 onDestory Fragment1因为已经被回收,又走onCreate,Fragment2被回收。 这两种方式显然都不满足我的需求,且与生命周期图不同。因为我需要在用户看见/看不见Fragment时register和unregister BroadcastReceiver之类的东西(onHiddenChanged也能实现,但第一次载入显示,以及销毁时不会走onHiddenChanged方法),也不希望用户回到上一个Fragment就重新创建整个Fragment,因为这样消耗资源。 看了ApiDemo,发现也是用replace方法,但是,我少了一行:

ft.addToBackStack(null);

在replace时加上这行,可以把原来的Fragment放入栈中,走onDestoryView方法,但不会onDestory,返回时,直接onCreateView,不再onCreate. 返回直接调用popBackStack()方法:

getFragmentManager().popBackStack();

JFinal官方文档只有Eclipse的配置,但已经习惯了Intellij IDEA,再转回到弱智的Eclipse,实在受不了。 环境是Mac. 先装Tomcat,http://tomcat.apache.org/download-80.cgi,下载Core tar.gz包,解压到合适的位置,比如:/Users/xxx/Documents/Applications/apache-tomcat-8.0.12,Tomcat是免安装的,解压即可使用。 Intellij IDEA必须是Ultimate Edition,免费的社区版是不行的,免费30天。 启动Intellij IDEA,创建Empty Project,完成后,创建新的Module,选择Java-Jave EE-Web Application(3.1),如下图: 651A59EB-1311-4030-AD33-509EB672A4BF 左侧Project Settings切到Artifacts,按+号创建 Web Application:Exploded->From Modules和Web Application:Archive->For xxx.第一个用于部署到tomcat,第二个用于生成war包。 455B37BF-959C-421E-8DC2-7F2B0F048283 增加启动配置: FC246ADB-8729-4ED8-8A8F-4E333D705946 Application Server设为我们刚下载的Tomcat(先点Configure…,把路径加进来),Open Browser的URL输入http://localhost:8080/目录名,切到Deployment选项卡,按+选择Artifact,选择xxx:war exploded,Application context输入/目录名,与前面的URL路径相同,保存。 改一下index.jsp,随便在body里输入点内容,运行看看能不能看到输出,有输出说明已配好。 接下来在WEB-INF目录下创建lib目录,把JFinal的jar以及其他用到的jar放进来,全选这些jar,点右键,Add as library… 大功告成,接下来看JFinal手册开发即可。

需求:安装squid代理,账号认证才能使用 安装: sudo apt-get install squid -y 安装apache2-utils生成账号 sudo apt-get install apache2-utils 生成账号: htpasswd -c /etc/squid3/passwd username 输入两次密码 编辑/etc/squid3/squid.conf,加入: auth_param basic program /usr/lib/squid3/basic_ncsa_auth /etc/squid3/passwd acl ncsa_users proxy_auth REQUIRED http_access allow ncsa_users 重启服务 service squid3 restart 默认squid是不允许匿名访问的。

除了严格模式外,还可以通过打印主线程方法栈的方式找到耗时操作:

        new Thread(){
            public void run(){
                while (true)
                {
                    try {
                        Map map=Thread.getAllStackTraces();
                       Set> stackTraceElementEntry=map.entrySet();
                        for(Map.Entry entry:stackTraceElementEntry)
                        {
                            Thread t=entry.getKey();
                            StackTraceElement[] stackTraceElements=t.getStackTrace();
                            if(t.getName().equals("main"))
                            {
                                String Tag="STACK_TRACE";
                                for(StackTraceElement stackTraceElement:stackTraceElements)
                                {
                                    Log.d(Tag,stackTraceElement.getLineNumber()+" "+stackTraceElement.getClassName()+stackTraceElement.getMethodName());
                                }
                            }
                        }
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();

未捕捉的异常会让应用Crash,如果是在用户处发生异常,我们无法得到日志,不好解决问题,友盟集成了错误日志收集功能,但我们也可以自己捕捉异常: 定义UnCaughtExceptionHandler,用于处理异常:

public class UnCaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        logToSdcard(thread,ex);
    }

    public static void logToSdcard(Thread thread,Throwable ex) {
        String logFilePath = "";
        FileWriter fw = null;
        PrintWriter pw = null;
        try {
            logFilePath = Environment.getExternalStorageDirectory().getPath()+"/crash.log";
            File logFile = new File(logFilePath);
            if (!logFile.exists()) {
                logFile.createNewFile();
            }
            fw = new FileWriter(logFile,true);
            pw = new PrintWriter(fw);
            pw.println(String.format("%s\t%s\t%s\t", new Date().toLocaleString(), thread.getName(), ex.toString()));
            Throwable cause= ex.getCause();
            StackTraceElement[] stackTraceElements=cause.getStackTrace();
            for (StackTraceElement stackTraceElement:stackTraceElements)
            {
                pw.println(String.format("%s\t%s\t%s\t", stackTraceElement.getClassName(), stackTraceElement.getLineNumber(), stackTraceElement.getMethodName()));
            }
            pw.close();
            fw.close();
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(pw != null){ try { pw.close(); } catch (Exception e) { }}
            if(fw != null){ try { fw.close(); } catch (Exception e) { }}
        }
    }
}

然后在Application中设置默认异常处理器:

Thread.setDefaultUncaughtExceptionHandler(
                new UnCaughtExceptionHandler());