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