Android真机调试新姿势:无线连接

在进行Android开发时,一般我们都是用usb线把手机和电脑连接起来进行调试工作。但如果你觉得这样不够酷的话,可以尝试一下无线连接,颇简单,GO!

准备工作

  • 手机和电脑需要在同一个局域网
  • 准备一条数据线——(what?不是说无线连接吗?!别着急,这只是第一次设置时用到的,以后再连接就不需要数据线了)
  • 你需要知道怎么执行adb命令(不知道的话请自行Google)

开始

1. 打开手机的5555端口

让手机在指定的端口可以接收到TCP/IP连接。(当然,也可以不用5555,用5556或者9999等都可以,只要你喜欢)

  1. 确保手机开启了usb调试
  2. 用usb线把手机和电脑连接起来
  3. 执行命令:
    adb tcpip 5555

执行成功后就可以把usb线拔掉了。

2. 找到手机的IP地址

一般在 设置-关于手机-状态信息-IP地址可以找到。 比如,我这里看到手机的IP地址是192.168.1.108

3. 通过IP地址和端口连接手机

执行命令: adb connect 192.168.1.108:5555

3.1 如果提示

connected to 192.168.1.108:5555

则表示连接成功

3.2 如果提示

unable to connect to 192.168.1.108:5555: Operation timed out

——可能你的IP地址输错了;或者adb服务不可用;或者手机跟电脑没有正确地处在一个局域网中;或者链接被代理Block了等等等…

3.3 如果提示

unable to connect to 192.168.1.108:5555: Connection refused

—— 可能你手机的5555端口没有正确打开;或者有防火墙拦截等…

4. 如果没有连接成功

如果出现了3.2或3.3的错误提示,或者其他任何错误,都可以尝试重启一下adb服务:

adb kill-server

然后再重新进行尝试。

5. 连接成功

如果连接成功的话,执行以下命令查看当前连接的设备列表: adb devices 可以看到连接的设备,像这样

$ adb devices List of devices attached 192.168.1.108:5555 device

——恭喜你,从此可以摆脱对数据线的依赖了。

总结&其他

  1. 更换一个网络环境(比如把手机和电脑从公司带回了家里),一般只需要按照新的手机IP重新进行一下connect即可。
  2. 但是如果手机重启了,就需要重新连接数据线再次开启5555端口了。
  3. 当然开启5555端口也并非必须通过adb,也有一些方法可以直接在手机上操作打开。但这些方法一般都需要root权限,如果你想要尝试在手机上进行开启,请注意安全。
  4. 有利就有弊——无线调试较有线调试而言,优势自不必说,缺点是无线数据的传输会比有线要慢一些。
  5. 还有一点,自从用了无线调试之后,我那常年满电的测试机,现在需要时不时的进行充电了~~~
    o(╯□╰)o

有用的链接:
https://developer.android.com/studio/command-line/adb.html http://stackoverflow.com/questions/23936781/unable-to-connect-android-device-over-adb-tcp-ip


Also in :
http://www.barryzhang.com
https://barryhappy.github.io
http://www.jianshu.com/users/e4607fd59d0d/latest_articles
http://blog.csdn.net/barryhappy


本文链接:http://www.barryzhang.com/?p=457

【Android】WebView:onReceiveError的应用与变迁

onReceiveError是WebViewClient提供的方法,用于网页产生错误时进行回调处理。

1. 旧版的onReceiveError

在API23之前,该方法的签名是:

public void onReceivedError(WebView view, int errorCode,String description, String failingUrl);

文档是:

Report an error to the host application. These errors are unrecoverable (i.e. the main resource is unavailable). The errorCode parameter corresponds to one of the ERROR_* constants.

简单来说,onReceivedError只有在遇到不可用的(unrecoverable)错误时,才会被调用)。
比如,当WebView加载链接www.barryzhang.com时,”不可用”的情况有可以包括有:

  • 没有网络连接

  • 连接超时

  • 找不到页面www.barryzhang.com

而下面的情况则不会被报告:

  • 网页内引用其他资源加载错误,比如图片、css不可用
  • js执行错误

2. 应用:显示个自定义ERROR界面

基于以上特性,所以它可以用来处理网页加载不出来的情况,比如显示一段友好的提示语、一个重试按钮等。
比如像这样:

@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
    super.onReceivedError(view, errorCode, description, failingUrl);
    layoutError.setVisibility(View.VISIBLE); 
    textViewErrorMessage.setText("(错误码:" + errorCode + "  " + description + ")"  );
}

——这么做的还有一个原因是,虽然默认的网页错误样式每个ROM都可能不一样,但是却是一样的丑……,来个对比图感受一下,从左到右依次是:MIUI(Android5.0.2)、Nexus5X(Android7)、以及自定义之后的效果:

onReceiveErro

3. 新版的onReceiveError

So far so good, but~
API23(Android6),Google对onReceiveError进行了一次改版重载,并且把老版本的废弃了,ㄒoㄒ~~
签名改成了这样:

public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error);

文档改成了:

Report web resource loading error to the host application. These errors usually indicate inability to connect to the server. Note that unlike the deprecated version of the callback,the new version will be called for any resource (iframe, image, etc), not just for the main page. Thus, it is recommended to perform minimum required work in this callback.

新版的onReceiveError能接收到的错误更多,不再局限于之前的”不可用”的情况——好像是比之前更强大了。
但是,这时候如果我们依然用使用旧版本的方式来使用新版,像这样:

@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
    // !!在新版的onReceivedError中,沿用之前的处理逻辑(这是错误的示例!!)
    super.onReceivedError(view, errorCode, description, failingUrl);
    layoutError.setVisibility(View.VISIBLE); 
    textViewErrorMessage.setText("(错误码:" + error.getErrorCode() + "  " + error.getDescription().toString() + ")"  );
}

这会导致的问题是:在Android6.0以上的机器上,网页中的任意一个资源获取不到(比如字体),网页就很可能显示自定义的错误界面。尤其是如果Html用了本地化技术,’ERR_FILE_NOT_FOUND’开始变得特别常见。

4. 如何像在老版本一样工作?

4.1 继续用老版本呢?

Bingo!可以,起码从目前来看,测试结果表明至少在Andoid6以及Android7上是可以工作的。

然而,终究,使用已废弃的API终究是不太优雅——说不定哪个版本就突然不能用了,仿佛像个定时炸弹一样。

4.2 isForMainFrame

我们注意到新版的onReceivedError跟老版相比,多了一个WebResourceRequest参数,而WebResourceRequest有一个方法叫做isForMainFrame,描述为:

Gets whether the request was made for the main frame
获取当前的网络请求是否是为main frame创建的.

加上这个条件判断是来试试?

@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
    super.onReceivedError(view, errorCode, description, failingUrl);
    if(request.isForMainFrame()){// 在这里加上个判断
        // 显示错误界面
    }
}

实验证明这个方法是有效的。

4.3 当然,也还有其他方法

可以这样,直接上代码:

@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
    super.onReceivedError(view, errorCode, description, failingUrl);
     if (request.getUrl().toString() .equals(getUrl())) {// 在这里加上个判断
        // 显示错误界面
    }
}

原理是:用请求的url来判断,如果出错的url跟webView当前加载的url一致,就显示错误页面。
↑↑经测试,也能通过~

总结

总而言之,最终的代码这样写,可以同时兼容新旧版本:

    // 旧版本,会在新版本中也可能被调用,所以加上一个判断,防止重复显示
    @Override
    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
        super.onReceivedError(view, errorCode, description, failingUrl);
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
            return;
        }   
        // 在这里显示自定义错误页
    }

    // 新版本,只会在Android6及以上调用
    @TargetApi(Build.VERSION_CODES.M)
    @Override
    public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { 
        super.onReceivedError(view, request, error);
        if (request.isForMainFrame()){ // 或者: if(request.getUrl().toString() .equals(getUrl()))
            // 在这里显示自定义错误页
        }
    }

【Android】你可能还不知道的elevation、以及Z值等

elevation、以及Z值——是什么?

众所周知,with和height是所有View的基础属性。用一个二维坐标系来描述手机屏幕,那么它们就分别表示了View在坐标系上x、y方向上值 ——这是我们一直都习惯的自然表示。
然而,从Android5.0(API21)开始,Google引入了一个z值,把二维坐标系强行改成了三维。

在Android API21,新添加了一个属性:android:elevation,用以在xml定义View的深度(高度),也即z方向的值。
除了elevation之外,类似于已有的translationX、translationY,也相对应地新增了一个translationZ,用以在属性动画中动态改变Z值(使用View.setTranslationZ())。

Z = elevation + translationZ

有什么用处呢?

在引入了这个属性之后,主要影响有两个:

  1. 影响View的阴影
  2. 影响View相互阻挡顺序

1. 影响View的阴影

Z值会对View的阴影外观造成影响,但是不是对View大小造成影响。
拥有更大Z值的View会有一个更大但是更柔和的阴影——这跟我们生活的实际体验是一致的,官方给的效果图:

阴影效果

2. 影响View相互阻挡顺序

拥有更大Z值的View会挡住Z值比较小的View——即更大Z值的View会在最上层。
譬如,在正常的FrameLayout中,子View的绘制顺序是从上到下,也就是说,最后一个子View会显示到最上面,如果位置跟前面的View有重合,则会盖住前面的View。

  <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <TextView
        android:id="@+id/viewA"
        android:background="#f00"
        android:text="A"
        android:gravity="center"
        android:layout_width="100dp"
        android:layout_height="100dp" />

    <TextView
        android:id="@+id/viewB"
        android:background="#0f0"
        android:text="B"
        android:gravity="center"
        android:layout_marginLeft="60dp"
        android:layout_marginTop="60dp"
        android:layout_width="100dp"
        android:layout_height="100dp" />

    <!--ViewC有了一个elevation属性 -->
    <TextView
        android:id="@+id/viewC"
        android:layout_marginLeft="180dp"
        android:background="#f00"
        android:text="C"
        android:gravity="center"
        android:elevation="1dp"
        android:layout_width="100dp"
        android:layout_height="100dp" />
    <TextView
        android:id="@+id/viewD"
        android:background="#0f0"
        android:text="D"
        android:gravity="center"
        android:layout_marginLeft="240dp"
        android:layout_marginTop="60dp"
        android:layout_width="100dp"
        android:layout_height="100dp" />
</FrameLayout>

比如,上面的xml代码,效果如下图所示:

对比图

  • 先看ViewA、ViewB,因为ViewB是第二个子View,ViewA是第一个,所以B会覆盖在A的上面。
  • 然后ViewC、D,跟AB相比较,区别就在于ViewC多了一个elevation属性,有了一个比ViewD更大的Z值,所以,即使它在ViewD的前面,但是依然能够盖住D~ (ViewC:因为朕站的更高,哇哈哈~ )

还有CardView

为什么会提到CardView呢?因为CardView可以算作是一个官方使用的Z值的示例了。

CardView 扩展 FrameLayout 类别并让您能够显示卡片内的信息,这些信息在整个平台中拥有一致的呈现方式。CardView 小组件可拥有阴影和圆角。

CardView是在v7支持包里面的,在API<21时,实现方式是padding+绘制阴影;而在在API>=21时,就是用elevation属性来实现的啦!

知道了这些,也可以解释一些以前觉得诡异的View覆盖的问题了,比如:我明明在CardView的上层放了一个Button,为什么Button看不到了???
(傻孩子,因为CardView默认的elevation的呀)


可能有用的链接:
https://developer.android.com/training/material/shadows-clipping.html
https://developer.android.com/training/material/lists-cards.html
https://developer.android.com/reference/android/support/v7/widget/CardView.html


本文链接:http://www.barryzhang.com/?p=444&preview=true

诡异的NoClassDefFoundError错误——也可能是65536引起的

诡异的NoClassDefFoundError错误

一 场景

症状一

本来好好的App,在引入了某个第三方库之后,忽然就开始报错了:

Caused by: java.lang.ClassNotFoundException: Didn’t find class “com.yourapp.XXX”

ClassNotFoundException——这是个很常见的错误啊,加载某些类的时候没找到嘛!
然而这次的诡异之处在于,这个com.yourapp.XXX明明就在那里,Android系统你为啥找不到呢,难道见鬼了么。

症状二

经过测试发现,只有Android2.x、Android4.x的机型会出现这种情况,Android5.x/6.x则能顺利通过

二 原因呢

如果你经过反复的Clean Project、 Rebuild Project、把某个包冲删除重新加入、重新安装app…… 还是没有找到原因的话,那很有可能就是因为那个著名的the 64K Reference Limit问题了。

名词解释: Android application (APK) files contain executable bytecode files in the form of Dalvik Executable (DEX) files, which contain the compiled code used to run your app. The Dalvik Executable specification limits the total number of methods that can be referenced within a single DEX file to 65,536—including Android framework methods, library methods, and methods in your own code. In the context of computer science, the term Kilo, K, denotes 1024 (or 2^10). Because 65,536 is equal to 64 X 1024, this limit is referred to as the ’64K reference limit

用中国话说:就是在Android中,由于某些原因,会导致单个Dex文件中最多只能容纳65536(64k)个方法,如果app中的方法数量多于65536个,就会导致这种错误。

千万不要觉得65536很多啊

一般在项目中,我们自己收写的代码只是很小一部分,大部分代码是在你引用的第三方轮子中啊,比如这些最常用的:

Name | Method Count ——— | ————- Gson 2.3 | 1,243 Jackson 3.4.3 | 6,731 Android Support V4 21 | 8,078
所以如果用的轮子多了,分分钟就会到了64k大限了。

这个问题有时会有其他的日志:

Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536

或者:

Too many field references: 131000; max is 65536. You may try using –multi-dex option.

如果是这两个报错,问题就明显多了,一看到65536这个神奇的数字就可以定位到这个病因了。

三 解决方案

知道病因之后,治病就简单了

精简代码,去除冗余

  • 经常清理一些过期不要的代码是个好习惯
  • 如果有功能类似的轮子也可以只保留一个,比如Gson/Jackson、Fresco/Glide、EventBus/Otto

开启ProGuard

自动去除一些未使用的代码,不过要注意很多轮子中的ProGuard配置,不然可能会导致动态加载的一些方法失效

终极方案MultiDex

名词解释:MultiDex allows you to use multiple DEX files contained within one APK. With a few steps, your classes will split automatically into several DEX files (classes.dex, classes2.dex, classes3.dex, etc) in case you reach the method index limit. Information on how to integrate MultiDex into your application will follow.

用中国话说,MultiDex就是一项技术,可以让一个apk中包含多个dex文件,每个dex文件中都不超过64k个方法,这样就OK啦

开启MultiDex方法

如果Android 5.0(API 21)以上会自动支持MultiDex,当然目前(2016年)我们的app可能不能只支持到API21了,所以还是需要在项目中配置的,需要如下三步:

1 在build.grade中配置defaultConfig:

defaultConfig {
...
// Enabling multidex support.
multiDexEnabled true
}

2 在build.grade中配置dependencies:

dependencies {
compile 'com.android.support:multidex:1.0.0'
}

3 使用MultiDexApplication取代Application:

① 如果没有自定义Application,那么在AndroidManifest.xml中指定MultiDexApplication即可
② 如果有自定义的MyApplaction extends Application,那么改成MyApplaction extends MultiDexApplication
③ 如果有自定义的MyApplaction继承了一个不能修改的XApplication,那么覆盖attachBaseContext()方法,在其中调用一下MultiDex.install(this)也可以。

四 链接

ProGuard: https://developer.android.com/studio/build/shrink-code.html
Multidex官方指南: https://developer.android.com/studio/build/multidex.html

ps:WordPress的MD插件不大好,文章格式有些乱,懒得校正了,就这样吧。


以上。
本文链接:http://www.barryzhang.com/archives/435

Android: NullPointerException when using RelativeLayout with measure()

使用measure()方法计算view的高度时,如果view中含有RelativeLayout布局,就有可能出现这样的错误:

07-13 13:18:34.330: E/AndroidRuntime(12098): java.lang.NullPointerException
07-13 13:18:34.330: E/AndroidRuntime(12098): at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:465)
07-13 13:18:34.330: E/AndroidRuntime(12098):at android.view.View.measure(View.java:15297)
……

大概算是Android的一个BUG了,Android4.4.4版本以后就不会有这个问题了。


解决方法是——
判断一下系统版本,如果大于等于4.4.4就无视,否则的话:

  1. 在这个view中不要用RelativeLayout布局了,改成LinerLayout或者FrameLayout啥的……

  2. 在调用measure()方法之前,判断一下view.getLayoutParams()的值,如果为null,就给丫随便设置一个layoutParams。

    view.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth,desiredHeight));

    当然这样你measure计算的值有可能会不准确,不过起码不会crash了呀……
    呵呵呵呵呵……

推荐用第一个方法。


http://www.barryzhang.com/archives/423

下载Android Build-tools 19.1.0

准备从Eclipse转到Android Studio了。今天尝试Android Studio的时候,被它提醒我SDK的Android Build-tools版本过低,需要升级。
于是打开Android SDK Manager,它顺利地帮我找到了Android SDK Build-tools的19.1版本,但是下载的时候却死活下载不了——Android SDK Manager在国内一向不稳定,时好时坏,而且今天在我已经搭了梯子的情况下依旧下载不了。
无奈,只得手动下载,但是找了一圈,居然没找到Google官方的下载链接,在http://developer.android.com/sdk/index.html上只找到了Android tools跟IDE的下载链接。


好吧,下面是手动分析找下载链接的过程:

iamge1
↑这个是Android SDK Manager的管理界面,然后查看它的日志↓:
iamge2
发现SDK的列表是从一个xml中解析的: https://dl-ssl.google.com/android/repository/repository-8.xml
OK,然后用浏览器打开这个地址:
xml文件果然就是这些SDK列表的信息,然后查找我所需要的Android SDK Build-tools 19.1,Duang~ 看到了一个叫做sdk:url的节点:
iamge2
显示url是build-tools_r19.1-macosx.zip。再然后,通过尝试,发现完整的url是https://dl-ssl.google.com/android/repository/build-tools_r19.1-macosx.zip——直接访问,就下载到了这个build-tools_r19.1-macosx.zipzip包了,然后丢到本地sdk的build-tools目录下,biu~ 搞定!



本文:http://www.barryzhang.com/archives/413

Android:防止过快点击造成多次事件

Android:防止过快点击造成多次事件

问题

onClick事件是Android开发中最常见的事件。比如,一个submitButton,功能是点击之后会提交一个订单,
则一般代码如下,其中submitOrder()函数会跳转到下一页进行处理 :

    //代码0
    submitButton.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            submitOrder();
        }
    }); 

正常情况下这段代码是没什么问题的,但是Android设备的机型性能等千差万别,如果碰到比较卡的手机,则有可能出现submitOrder()函数跳转页面出现延迟的现象。碰到这种现象,则用户就很有可能再次点击一次,从而造成函数被调用两次,出现重复订单的BUG。
一般地,碰到这现象,首先就会想到的就是在点击之后把submitButton设置为不可点击:

    //代码1
    submitButton.setClickable(false);
    //或者   
    submitButton.setEnabled(false); 

此方法也确实有效,不过如果submitOrder()方法没有成功,需要再次提交订单时又需要再重复把submitButton设置为可点击状态。如果类似的button比较多时,就显得比较麻烦、混乱。

方案


————-So,接下来就是咱的显得比较优雅的方法啦,~(@^_^@)~ ———————


自定义一个NoDoubleClickListener,继承自OnClickListener

    //代码2
    public abstract class NoDoubleClickListener implements OnClickListener {

        public static final int MIN_CLICK_DELAY_TIME = 1000;
        private long lastClickTime = 0;

        @Override
        public void onClick(View v) {
            long currentTime = Calendar.getInstance().getTimeInMillis();
            if (currentTime - lastClickTime > MIN_CLICK_DELAY_TIME) {
                lastClickTime = currentTime;
                onNoDoubleClick(v);
            } 
        }   
    }

使用方法—— 给submitButton设置点击事件时用NoDoubleClickListener代替OnClickListener,并且实现方法onNoDoubleClick代替onClick即可,像这样:

    //代码3
    submitButton.setOnClickListener(new NoDoubleClickListener() {
        @Override
        public void onNoDoubleClick(View v) {
            submitOrder();
        }
    }); 

原理:

很简单,见代码……
就是用onNoDoubleClick代替onClick处理具体的操作,在onClick方法中加一个判断:在接收到点击事件之后,先判断一下时间,如果距离上次处理操作不足MIN_CLICK_DELAY_TIME,就忽视——即能防止误操作的连续点击导致重复事件。

MIN_CLICK_DELAY_TIME可调。

优势

好处是不用改变原有代码的逻辑,就只需要两个替换:NoDoubleClickListener代替OnClickListener,onNoDoubleClick代替onClick。 代码的结构等都不需要做改变(对比上面的代码0跟代码3),不需要关心处理更改button的状态这些额外判断逻辑,只需要关注业务逻辑即可,简洁优雅~



本文地址:http://www.barryzhang.com/archives/410

JAVA的奇技淫巧——不定参数

在知乎的回答,居然一个赞的都木有,放这里咯~~ o(╯□╰)o
我真觉得不定参数是很牛逼的东西,本质上还是数组参数的简化而已,但是写起来真是特别方便,牛逼的不行~
@See: Java 有什么奇技淫巧? – 腾儿飞(张新强) 的回答 – 知乎


不定参数啊!

比如,我要设置N个view的可视性,一般需要写这N句代码:

textView1.setVisibility(visibility);
textView2.setVisibility(visibility);
listView.setVisibility(visibility);
imageView.setVisibility(visibility);

如果我有一个不定参数的函数话:一个函数,可以传0~N个参数

private void setViewVisibility(View... views){
    int visibility = shouldVisiable ? View.VISIBLE : View.GONE; 
    for(View view: views){
        view.setVisibility(visibility);
    }
}

就可以这么写了:

setViewVisibility(textView1,textView2,listView,imageView);

还可以这么写:

setViewVisibility(textView1,textView2);
setViewVisibility(listView,imageView);

还可以这么写:

setViewVisibility(textView1);
setViewVisibility(textView2,listView,imageView);

还可以这么写:

setViewVisibility();
setViewVisibility();
setViewVisibility();
setViewVisibility(textView1);
setViewVisibility(textView2);
setViewVisibility(listView,imageView);
setViewVisibility();
setViewVisibility();

就是这么任性~!! 就是这么吊~!!!

小图片



本文链接: http://www.barryzhang.com/archives/405

自定义DialogFragment的内容和按钮

小问题,记录下~


Android4.0以后开始推荐使用DialogFragment代替Dialog。Android的官方文档中给了两个示例:

  • 一个Basic Dialog
    示例了如何自定义窗口内容——重写onCreateView方法。
  • 一个Alert Dialog
    示例了如何自定义弹窗的正负按钮——重写onCreateDialog方法。

好的,那么问题来了

在实际应用中经常是需要既自定义窗口内容、又需要自定义按钮的。
这时候如果我们按图索骥,把DialogFragment的onCreateView和onCreateDialog方法都重写的话,会发现——Bong!异常~ 诸如“AndroidRuntimeException: requestFeature() must be called before adding content”的就出现了。

这个异常出现的原因可以看:stackoverflow的这个问题中Freerider的答案以及下面评论。
摘抄一下:“ You can override both (in fact the DialogFragment says so), the problem comes when you try to inflate the view after having already creating the dialog view. You can still do other things in onCreateView, like use the savedInstanceState, without causing the exception.”

然后是解决方案:

既然两个方法不能同时重写,所以就选择一个进行重写:
重写onCreateDialog方法,参照官方示例即可以自定义按钮,然后对其作修改,使之能自定义view——在AlertDialog.Builder进行create()创建dialog之前,使用AlertDialog.Builder的setView(view)方法,其中view是自定view。

来感受一下区别~
这是Google给的示例:

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    int title = getArguments().getInt("title");
    return new AlertDialog.Builder(getActivity())
            .setIcon(R.drawable.alert_dialog_icon)
            .setTitle(title)
            .setPositiveButton(R.string.alert_dialog_ok, 。。。)
            .setNegativeButton(R.string.alert_dialog_cancel, 。。。)
            .create();
}     

这是修改之后的:

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    //inflater在前面构造函数中实例化
    View v = inflater.inflate(R.layout.dialog,null);
    imageGridView = (GridView) v.findViewById(R.id.gridViewImage);
    //自定义view,bla~bla~
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    return builder.setView(v)
            .setIcon(android.R.drawable.ic_dialog_alert)
            .setTitle(title)
            .setCancelable(false)
            .setPositiveButton(R.string.alert_dialog_ok, 。。。)
            .setNegativeButton(R.string.alert_dialog_cancel, 。。。)
            .create();
}

本文链接: http://www.barryzhang.com/archives/396

Dribbble非官方客户端Android版

Dribbble客户端

上个周末用了整整两天的时间完成了这个——Dribbble网站(http://www.dribbble.com/)的Android版非官方客户端,这周又打磨一下,做些修改,现在基本能看了。

感谢依米吴同学的设计,以及小瓶子IOS版本参考。

目前已经完成的功能有:

  • 浏览debuts、erveryone、popular分类的时间线
  • 点击图像查看详情(评论等)
  • 点击作者头像查看作者信息
  • 收藏供离线查看

下版本待改进的地方:

  • 收藏功能 (目前是把数据存到SD卡,图像依赖于缓存所以还不太可靠)
  • 目前评论只能加载第一页
  • 某些时候(可能是图片过小)圆形图片绘制的会很诡异。

参考了如下代码:

应用市场正在审核,现在可以在这里下载
待我再优化下,会把代码放出来。

以下是截图:
lunch
main
shot
player


本文链接http://www.barryzhang.com/archives/392