Don't hold references to any type of UI specific objects in any threading scenarios.
Don't declare your task as an inner class of an activity.
Looper class keeps the thread alive, holds a message queue and pop works off a queue and execute on. Handler class helps put work at the head, the tail or even set a time-based delay.
Help get work on/off the UI thread.
- Basically, all AsyncTasks are created in a same thread. That means them will execute in a serial fashion from a single message queue.
- There is a way to force AsyncTask works in thread-pooled way : AsyncTask.executeOnExecutor
Dedicate thread for API callbacks.
- HandlerThread is a nifty solution for the work that not deal with UI updates.
- Don't forget to assign the priority because CPU can only execute a few parallel threads.
Run a lot of parallel small works.
It's ideal for background tasks. It also helps get intents off UI thread.
It's the easiest way to update UIs by running on AsyncTask, and HandlerThread is also a excellent solution for the work that not deal with UI updates.
- TCP/IP specifies how data is exchanged over the internet.
- Socket is kind of like APIs which packages TCP and UDP operations.
- HTTP, FTP, SMTP and the other protocols map to the application layer which only standardizes communication and depends upon the underlying transport layer protocols to establish host-to-host data transfer channels and manage the data exchange in a client-server or peer-to-peer networking model.
- In real life scenario examples:
- TCP : FTP, HTTP
- UDP : Voice and Video, Streaming movies online
- Android 6.0 release removes support for the Apache HTTP client. You still want to import this library while your target API is higher than 23, you have to declare the following codes in build.gradle:
android {
useLibrary 'org.apache.http.legacy'
}
- Create an HttpClient for the whole project, and make ThreadSafeClientConnManager to manager the thread. Initialize HttpClient in MyApplication and use MyApache which has been packaged doGet() and doPost.
- ApacheFragment
- HttpClient settings:MyApplication, MyApache
- HttpURLConnectionFragment
- HttpURLConnection settings:MyHttpURLConnection
- Download a single file with multiple threads
- Show the progressbar
- DownloaderFragment
- DownloaderAsyncTask
Under normal usage, the starting point for any developer should be to add as an aggressive caching strategy to the files in the application that will not change. Normally this will include static files that are served by the application such as images, CSS file and Javascript files. As these files are typically re-requested on each page, a large performance improvement can be had with little effort.
An application using HTTP cache headers is able to control this caching behavior and alleviate server-side load. For example, you got a HTTP response like this.
HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Type: image/png
Last-Modified: Tue, 08 Nov 2016 06:59:00 GMT
Accept-Ranges: bytes
Date: Thu, 10 Nov 2016 02:48:50 GMT
Content-Length: 3534
You can find something about cache in HTTP headers
Cache-Control: no-cache
The upper description is equal to
Cache-Control: max-age=0 (seconds)
And you can also consider it to be
Cache-Control: public or private
Expires: right now
- Cache-Control
The Cache-Control
header is the most important header to set as it effectively ‘switches on’ caching in the browser.
value | meaning |
---|---|
no-store | No cache |
no-cache | It's no need to cache the HTTP response you got, but still allowing caching |
public | 1. It can be cached, even if it has HTTP authentication associated with it. 2. Public resources can be cached not only by the end-user’s browser but also by any intermediate proxies that may be serving many other users as well. |
private | 1. Only control where the response may be cached, and cannot ensure the privacy of the message content. 2. Private resources are bypassed by intermediate proxies and can only be cached by the end-client. |
max-age=300 | Response can be cached for up to 5 minutes. And where it is cached refer to 'private' or 'public' |
- Expires
Superseded by Cache-Control
header. And Cache-Control
has priority over Expires
.
If both Expires
and max-age
are set max-age
will take precedence.
Expires
header defines a precise time but some of the users can't synchronize the latest response because they are in other time zones.
Expires:Tue, 03 May 2016 09:33:34 GMT
- Last-Modified
You get the response headers like that
Cache-Control:public, max-age=31536000
Last-Modified: Mon, 03 Jan 2011 17:45:57 GMT
And next time, your request headers contain
Last-Modified: Mon, 03 Jan 2011 17:45:57 GMT
Your request must contain If-Modified-Since
so that the server will check the timestamp.
If the resource hasn't changed since Mon, 03 Jan 2011 17:45:57 GMT
, the server'll return 304 with an empty body.
- ETag
ETag (or Entity Tag) is typically a hash or some other fingerprint of the contents of the file (for instance, an MD5 hash).
You get the response headers like that
Cache-Control:public, max-age=31536000
ETag:"751F63A30AB5F98F855D1D90D217B356"
And next time, your request headers contain
If-None-Match: "751F63A30AB5F98F855D1D90D217B356"
If the resource hasn't changed, the server'll return 304 with an empty body.
Even if your cache is up, it doesn't mean your cache is not working. Your response might contain an ETag which instructs the client to cache it for up to a specific period and provides a validation token ( MD5 or something ) that can be used after the response has expired to check if the resource has been modified. If the token hasn't been changed, the server returns a "304 Not Modified" response.
So your cache strategy will be:
First of all, make sure your browser, application or something are available to cache responses. Then check whether the response has expired.
Expires:current time + maxAge(=0)
or
Cache-Control: max-age=(0)
If your cache is not available, then you request ETag (with If-None-Match) or Last-Modified (with If-Modified-Since) to your server (Of course you could alse use both of them to double-check). Your server would return 304 when it's okay to use the cache that has been stored or you get 200 with new resources.
-
Force to refresh F5:
Cache-Control:max-age=0
Ctrl + F5:Cache-Control:no-cache
orPragma:no-cache
-
No cache
Both values are required as IE uses no-cache
, and Firefox uses no-store
.
Cache-Control:no-cache, no-store
- WebView cache
- Client requests a https url
- There is a keypair in server.
- Server passes the public key to client.
- Client validates the public key and generate a key (I call it client key). If the public key is able to be truthed, client encrypts the client key with the public key.
- Client sends the encrypted client key to server.
- Server decrypts the client key with private key.
- Server sends messages encrypted with the client key to client.
- Client decrypts the messages with the client key.
In step 4, how does client know that public key is valid? Let CA (Certificate Authority) list tells client. There are hundreds of CAs in the world. Which CA you can trust depends on a CAs list in client. (Normally, your mobile phone had been saved a list of trusted CAs before you bought it.)
DO NOT IMPLEMENT "X509TrustManager" TO SKIP VALIDATION
That means man-in-the-middle attacks are allowed.
As I was mentioning, If you open a url (https://kyfw.12306.cn/otn/regist/init) with your Android device and you get an exception:
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
Because the CA of kyfw.12306.cn is not in default trusted CA list of your device.
In this scenario, if you are sure this website is trusted and you've got to request it, you create your SSLTrustManager which implements X509TrustManager and do nothing in the override methods. It means you skip certificates verification. Hackers can send you a fake public key to connect to client because you don't validate the public key in step 4, your device finally connect to the hacker's server.
There are two solutions, the last one is better.
-
Get the certificate of kyfw.12306.cn and keep it in assets folder. You add this certificate to trusted CA list of client.
After the end of the validity period, the certificate is no longer considered an acceptable. -
Get the certificate of CA which sponsors kyfw.12306.cn and keep it in assets folder. You add this certificate to the trusted CA list of client.
Normally, the CAs of the department sponsors specific domains have a longer validity period than domains. That's why this solution is recommended.
Android example
Take kyfw.12306.cn for example.
- Download the certificate of kyfw.12306.cn and add to assets file.
- Add this certificate to trustManager[]
- Let "HttpsURLConnection" trust this certificate
- Go to HttpURLConnectionFragment to see more.
Another example - request to github APIs
- Add the PEM formatted String of the certificate.
- Add this certificate to trustManager[]
- Let "HttpsURLConnection" trust this certificate
- Go to HttpURLConnectionFragment to see more.
Check SSL certificates here : https://www.ssllabs.com/ssltest/
ImageView + DiskLruCache
- Download a url list.
- Check internal or external storage of the device. If the images have had been cached, skip step 3 and show them.
- Download each image from the list and try to cache them.
- Show images whatever they have been cached.
Here is the example: GalleryFragment, ImageCardRVAdapter
Fresco - SimpleDraweeView
Three ways to deal with images:
- Show images directly by calling setImageURI().
- Prefetch images and show them at the same time. That means there're at least two threads - the one downloads the images and another displays the images.
- As the app launches, prefetch images and save them to your cache folder even though the fragment or activity which displays the images hasn't opened yet.
Here is the example: FrescoFragment, FrescoRVAdapter
Blocking socket
- Server : Run MySocket with eclipse
tcpSocketReceiver();
- Client : Run WebServices and open BlockingSocketFragment fragment on Android devices.
Non-blocking socket (NIO Socket)
- Server : Run MySocket with eclipse
startNIOSocket();
- Client : Run WebServices and open NIO_SocketFragment fragment on Android devices.
- Server : Run MySocket with eclipse
udpSocket();
- Client : Run WebServices and open UDP_SocketFragment fragment on Android devices.
MyWebView, FullWebViewFragment and NestedWebViewFragment supports the functions of...
- Going back to previous pages.
- Showing a ProgressBar while WebView is loading resources.
- Launching other apps installed in your device by url scheme.
- Handling JavaScript alert(), confirm() and prompt() and displaying the message with a used-defined dialog.
Before using JavaScript, you should have WebView enable JavaScript. Go to WebViewSettingsFragment to set.
- Calling Java functions from JavaScript
Two tips:
- Don't forget to ignore your JavaScriptInterface with Android proguard
- Add @JavascriptInterface Annotation and you can go to MyJavaScriptInterface to see more
In this project, all classes that can not be obfuscated implement IgnoreProguard interface.
In proguard-rules.pro
-keep public class com.catherine.webservices.toolkits.IgnoreProguard
-keep public class * implements com.catherine.webservices.toolkits.IgnoreProguard
-keepclassmembers class * implements com.catherine.webservices.toolkits.IgnoreProguard {
<methods>;
}
- Calling JavaScript functions from Java.
- Saving photos to your device from the Internet.
Save the image after long-clicking it.
- Visiting a HTTPS website and you get a SSL error.
Again, you could use https://kyfw.12306.cn/otn/regist/init to test.
OverrideonReceivedSslError()
and pop up a dialog to let users decide to continue (it would be unsafe maybe) or stop visiting the website.
- Switching desktop style or mobile style websites by user-agent
- Getting media and location permission
You need to add following permission in your AndroidManifest.xml And override
onGeolocationPermissionsShowPrompt()
andonPermissionRequest()
in WebChromeClient.
<!--getUserMedia-->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<!--location-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
- HTML5
Go to https://html5test.com/ to see the browser compatibility.
- Supporting Dom storage
- Supporting Web SQL database and IndexedDB
Web SQL has been deprecated by W3C IndexedDB is available on Android 4.4+
- Launching FileChooser You could also go to WebViewTestListFragment to test all the websites I listed.
WebViewSettingsFragment Set attributes of WebView that includes WebViewClient and WebSettings (setAllowFileAccess(), setJavaScriptEnabled(), setSupportZoom() and so forth.)
- Network info: NetworkAnalyticsFragment
- Device info: DeviceInfoActivity