1. 程式人生 > >Android開發中遇到的問題及小知識總結【一】

Android開發中遇到的問題及小知識總結【一】

PhotoView+ViewPager 發生java.lang.IllegalArgumentException: pointerIndex out of range異常

**描述:**當PhotoView 和 ViewPager 組合時 ,用雙指進行放大時 是沒有問題的,但是用雙指進行縮小的時候,程式就會崩掉

**原因:**多次觸發觸控式螢幕事件,導致對同一個事件處理的訊息過多,當第一個訊息已處理完事件並銷燬事件時,
由於該事件已銷燬但還沒來得及通知銷燬第二個同樣的訊息,當主執行緒執行第二個訊息時,由於獲取不了該事件,
所以丟擲異常。簡單理解就是2個控制元件對同一個MotionEvent出現了衝突.

**解決:**自定義一個類去繼承ViewPager ,然後重寫Viewpager的 onInterceptTouchEvent()的方法,捕捉該異常。

/**
 * Created by cxy
 * on 2017/7/5.
 * 解決  photoview 與viewpager 組合時 圖片縮放的錯誤 ;
 * 異常:.IllegalArgumentException: pointerIndex out of range
 */

public class PhotoViewPager extends ViewPager{

    public PhotoViewPager(Context context) {
        super(context);
    }

    public PhotoViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        try {
            return super.onInterceptTouchEvent(ev);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();
        }
        return false;
    }

}

viewpageradapter 呼叫notifyDataSetChanged()時不重新整理頁面.

**原因:**在getItemPosition()方法的原始碼中如果item的位置如果沒有發生變化,則返回POSITION_UNCHANGED。
如果返回了POSITION_NONE,表示該位置的item已經不存在了。預設的實現是假設item的位置永遠不會發生變化,
而返回POSITION_UNCHANGED。

**解決:**修改介面卡的寫法,覆蓋getItemPosition()方法,當呼叫notifyDataSetChanged時,
讓getItemPosition方法人為的返回POSITION_NONE,從而達到強迫viewpager重繪所有item的目的。

####當使用Fragment去巢狀另外一些子Fragment的時候,我們需要去管理子Fragment,這時候需要呼叫ChildFragmentManager去管理這些子Fragment,由此可能產生的Exception主要是: Java.lang.IllegalStateException: No activity

**描述:**當第一次從一個Activity啟動Fragment,然後再去啟動子Fragment的時候,存在指向Activity的變數,但當退出這些Fragment之後回到Activity,然後再進入Fragment的時候,這個變數變成null

原因:Fragment在detached之後都會被reset掉,但是它並沒有對ChildFragmentManager做reset,所以會造成ChildFragmentManager的狀態錯誤

**解決:**我們需要在Fragment被detached的時候去重置ChildFragmentManager

@Override
  public void onDetach() {
    super.onDetach();
    try {
      Field childFragmentManager = Fragment.class
          .getDeclaredField("mChildFragmentManager");
      childFragmentManager.setAccessible(true);
      childFragmentManager.set(this, null);

    } catch (NoSuchFieldException e) {
      throw new RuntimeException(e);
    } catch (IllegalAccessException e) {
      throw new RuntimeException(e);
    }
  }

使用Write_setting許可權出現java.lang.IllegalArgumentException: You cannot keep your settings in the secure settings.

在android 6.0及以後,WRITE_SETTINGS許可權的保護等級已經由原來的dangerous升級為signature,
這意味著我們的APP需要用系統簽名或者成為系統預裝軟體才能夠申請此許可權,並且還需要提示使用者跳轉到修改系統的設定介面去授予此許可權,debug模式是不能申請該許可權

didn’t find class on path dexpathlist

保證工程和引用庫檔案用同一個支援包,刪除build目錄,clean工程
eq:第一個activity引用android.app.activity包,第二個activity引用v7包的AppcompantActivity,這樣可能就會報找不到第一個activity

AndroidStudio打包時報錯The same input jar is specified twice

原因 是build.gradle檔案配置了
dependencies {
compile fileTree(include: '.jar’, dir: ‘libs’)
}
這裡面已經新增過jar包,但是又在混淆檔案proguard.cfg裡面又加了句-libraryjars libs/
**.jar,
將-libraryjars libs/***.jar 前面用#號註釋或者直接刪掉即可。

注意:sdk 通過 proguard 混淆程式碼時預設已經將 lib目錄中的 jar 都已經新增到打包指令碼中,所以不需要再次手動新增。

Activity當中的EditText的軟鍵盤彈出問題

這個在mainfest.xml中activity下面有一個屬性為windowSoftInputMode,它共有10個值可以配置,每個配置都對頁面輸入法彈出框影響不同

  1. stateUnspecified :即未指定狀態,當沒有設定android:windowSoftInputMode屬性的時候,預設是這樣的互動方式,系統會依據介面採取對應的軟鍵盤的顯示模式。比如當介面上僅僅有文字和button的時候,軟鍵盤就不會自己主動彈出。由於沒有輸入的必要
  2. stateUnchanged:即狀態不改變。就是當前介面的軟鍵盤狀態,取決於上一個介面的軟鍵盤狀態。比如當前介面鍵盤是隱藏的,那麼跳轉之後的介面,軟鍵盤也是隱藏的;當前介面是顯示的,那麼跳轉之後的介面,軟鍵盤也是顯示狀態
  3. stateHidden:假設我們設定了這個屬性,那麼鍵盤狀態一定是隱藏的,無論上個介面什麼狀態。也無論當前介面有沒有輸入的需求,反正就是不顯示。因此,我們能夠設定這個屬性,來控制軟鍵盤不自己主動的彈出
  4. stateAlwaysHidden:這個屬性也能夠讓軟鍵盤隱藏。
  5. stateVisible:能夠將軟鍵盤自動彈出來,即使在介面上沒有輸入框的情況下也能夠強制彈出來
  6. stateAlwaysVisible:也是可以主動將軟鍵盤彈出來,可是與stateVisible屬性有小小的不同之處。舉個樣例,當我們給A介面設定為stateVisible屬性,假設當前的介面鍵盤是顯示的,當我們跳轉到下個介面再回到當前介面的時候,鍵盤這個時候是隱藏的;可是假設我們設定為stateAlwaysVisible,我們跳轉到下個介面再次回來的時候。軟鍵盤是會顯示出來的
  7. adjustUnspecified:設定軟鍵盤與軟體的顯示內容之間的顯示關係。當沒有設定這個值的時候,這個選項也是預設的設定模式,第一:頁面沒有滾動控制元件的時候,當輸入框會被彈出軟鍵盤擋住的情況下,將輸入框上移,以保證輸入框處於使用者視野範圍,其它檢視不變,如果不會被擋住,頁面檢視位置不會變動;第二:頁面有滾動控制元件的時候,將頁面整體檢視上移,保證處於軟鍵盤上方
  8. adjustResize:同上,但是有兩點不同,第一:這個屬性是將Activity整個介面往上移動,保證處於軟鍵盤的上方,全部View可見;第二:會自動將軟鍵盤彈出
  9. adjustPan:與adjustUnspecified屬性類似,但是有一點不同,就是頁面有滾動控制元件的時候,只會保證輸入控制元件不被軟鍵盤擋住,其它檢視不保證
  10. adjustNothing:這個屬性沒有實際意義,軟鍵盤彈出的時候,頁面所有View不會變動

socket讀取的時候報java.net.SocketException: Connection reset

這是因為
1,如果一端的Socket被關閉(或主動關閉,或因為異常退出而 引起的關閉),另一端仍傳送資料,傳送的第一個資料包引發該異常(Connect reset by peer)。
2,一端退出,但退出時並未關閉該連線,另一端如果在從連線中讀資料則丟擲該異常(Connection reset)。
簡單的說就是在連線斷開後的讀和寫操作引起的。

socket連線的時候報java.net.ConnectException: Connection refused: connect

這是因為服務端沒有啟動,或者與服務端連線的埠或者ip不一致,意思就是連線不到相對應的服務端

查詢伺服器埠是否有資料發出

LINUX:
telnet 10.100.20.137 7780 #檢視10.100.20.137伺服器的7780是否有資料發出
tcpdump udp port 11011 #是否有資料走UDP協議往埠11011發
tcpdump tcp port 8888 #是否有資料走TCP協議往埠8888發

WIN方法:
winshark

端口占用情況

有時候在執行一些開發工具的時候經常會碰到埠被佔用的情況,比如adb執行埠被其它流氓軟體佔用,解決如下

  • 可以通過 netstat -ano,列出所有埠的情況
  • 通過netstat -aon|findstr “5037” (5037是adb埠)命令檢視這個埠所對應的程序PID
  • 輸入tasklist|findstr “2720” 檢視該pid對應程序的程序名稱(2720是程序pid)
  • 輸入taskkill /im sjk_daemon.exe /f 殺死程序名為sjk_daemon.exe的程序

字串拼接

在開發中通常使用 + 號來將幾個String進行拼接顯示到XML中的TextView標籤裡,這顯然是不合理的,可以使用getString方法進行更完美的實現

說到getString方法需要先說到三個約束符

  • %n$ms:n表示第幾個引數;m表示間隔幾個空格顯示,3表示一個空格,4表示兩個空格,以此類推;s表示這是一個String的約束符
  • %n$md:前面幾個符號與上面類似,只有d不同,表示這是整數的約束符
  • %n$mf:因為f表明這是一個浮點型資料的約束符,所以m表示保留幾位小數;.1表明保留一位小數,.2保留兩位小數,以此類推,數字前面的點號不要忘了

####舉例:
**eq1:**在strings.xml中定義一個格式約束符

<resources>
	<string name="format">%1$s(%2$d/%3$d),%4$s(%5$1.1f)</string>
</resources>

可以看到這裡總共是由2個String、2個整數、1個浮點陣列成
接下來在程式碼裡使用

String result = getString(R.string.format,"小明作業完成情況",8,16,"完成率",0.5);

打印出來的結果如下

小明作業完成情況(8/16),完成率(0.5)

**eq2:**上面的格式約束符是由純符號組成,也可以文字加符號一起

<resources>
	<string name="age">我今年%1$d歲了,來自%2$s</string>
</resources>

這裡需要使用format方法,其實你看getString原始碼實現,就知道最後也是呼叫的format方法

String age = String.format(getString(R.string.age),15,"北京");

列印結果

我今年15歲了,來自北京

**eq3:**如果需要文字的一部分用特殊顏色顯示,可以使用html

<string name="pay"><![CDATA[<b>應付:</b> <font color=#F09B02>¥%1$.2f</font>]]></string>
<string name="seller"><![CDATA[共<font color=#f37214>%1$d</font>件,合計: <font color=#f37214>¥%2$.2f</font> 元]]> </string>
mText.setText(Html.fromHtml(String.format(getResources().getString(R.string.pay),66.66)));

這裡面的應付兩個字也可以用上面的例子中的約束符替代,然後在程式碼裡可以動態顯示xxx應付,這樣就更加動態化了,適應性更強