首页 > 其他分享 >Android Asynchronous HTTPClient的实现和优化

Android Asynchronous HTTPClient的实现和优化

时间:2022-10-06 11:33:31浏览次数:85  
标签:Log void response TAG Asynchronous new Android public HTTPClient


大家知道Android对UI线程的反应时间要求很高,超过5秒钟直接ANR掉,根本不给你机会多等。


而Android应用与后端系统的交互是最基本的需求之一,如何实现高效的Asynchronous HTTPClient,确保UI线程在启动任务后交由后端异步处理与服务器端的通信,尤为关键。


Google过几个方案,要么太复杂要么不符合要求,基本都淘汰了,最后发现这一版本的实现不错,就拿来用了。

链接:​​Android Asynchronous HTTPClient tutorial​


后来发现了几个严重的问题,罗列如下:

1. 启用单独的线程后,简直如脱缰的野马,难以驾驭。

现象是:在调试的时候经常发现某个线程死掉(比如在服务器down掉的时候,由于线程无法连接而挂掉)

后果是:只能关掉模拟器,甚至还要重启eclipse,否者两者通信出现问题,再也不能继续联机调试


2. 异常的处理非常弱,Activity层难以捕捉并加以处理。

这个问题跟实现的机制有一定的关系,此实现根本就没提供好的异常处理机制,以便捕捉、反馈、处理合理的可预见性的异常,诸如:

1)UnknownHostException – 谁能确保手机的网络连接一直正常,信号一直满格?

2)HttpResponseException – 后端500的错误,说不定就蹦出来了

3)SocketTimeoutException – 超时也是太正常不过了,如果人家在荒山野岭(no 3G)摆弄超大的通信请求

4)诸如此类吧

所以改造就再说难免了。下面我贴出相关代码(import就省了吧这里),并加以简单注释说明,方面大家的理解。


首先定义AsyncHttpClient.java。这里的重点是超时的设置。另外我加了个cancelRequest,用以在切换Activity后取消掉原有Activity发出的所有的异步请求,因为一般情况下,切换了Activity后是不能再更新那个UI了,否则会抛出异常,直接导致应用crash掉,不过话说回来,这个cancel我发现好像不是那么给力(any feedback?)。


Java代码


​ ​

​​


1. public class AsyncHttpClient {
2. private static DefaultHttpClient httpClient;
3. public static int CONNECTION_TIMEOUT = 2*60*1000;
4. public static int SOCKET_TIMEOUT = 2*60*1000;
5. private static ConcurrentHashMap<Activity,AsyncHttpSender> tasks = new ConcurrentHashMap<Activity,AsyncHttpSender>();
6. public static void sendRequest(
7. final Activity currentActitity,
8. final HttpRequest request,
9. AsyncResponseListener callback) {
10. sendRequest(currentActitity, request, callback, CONNECTION_TIMEOUT, SOCKET_TIMEOUT);
11. }
12. public static void sendRequest(
13. final Activity currentActitity,
14. final HttpRequest request,
15. AsyncResponseListener callback,
16. int timeoutConnection,
17. int timeoutSocket) {
18. InputHolder input = new InputHolder(request, callback);
19. AsyncHttpSender sender = new AsyncHttpSender();
20. sender.execute(input);
21. tasks.put(currentActitity, sender);
22. }
23. public static void cancelRequest(final Activity currentActitity){
24. if(tasks==null || tasks.size()==0) return;
25. for (Activity key : tasks.keySet()) {
26. if(currentActitity == key){
27. AsyncTask<?,?,?> task = tasks.get(key);
28. if(task.getStatus()!=null && task.getStatus()!=AsyncTask.Status.FINISHED){
29. Log.i(TAG, "AsyncTask of " + task + " cancelled.");
30. task.cancel(true);
31. }
32. tasks.remove(key);
33. }
34. }
35. }
36. public static synchronized HttpClient getClient() {
37. if (httpClient == null){
38. //use following code to solve Adapter is detached error
39. //refer: http://stackoverflow.com/questions/5317882/android-handling-back-button-during-asynctask
40. BasicHttpParams params = new BasicHttpParams();
41. SchemeRegistry schemeRegistry = new SchemeRegistry();
42. schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
43. final SSLSocketFactory sslSocketFactory = SSLSocketFactory.getSocketFactory();
44. schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));
45. // Set the timeout in milliseconds until a connection is established.
46. HttpConnectionParams.setConnectionTimeout(params, CONNECTION_TIMEOUT);
47. // Set the default socket timeout (SO_TIMEOUT)
48. // in milliseconds which is the timeout for waiting for data.
49. HttpConnectionParams.setSoTimeout(params, SOCKET_TIMEOUT);
50. ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
51. httpClient = new DefaultHttpClient(cm, params);
52. }
53. return httpClient;
54. }
55. }

public class AsyncHttpClient { private static DefaultHttpClient httpClient; public static int CONNECTION_TIMEOUT = 2*60*1000; public static int SOCKET_TIMEOUT = 2*60*1000; private static ConcurrentHashMap<Activity,AsyncHttpSender> tasks = new ConcurrentHashMap<Activity,AsyncHttpSender>(); public static void sendRequest( final Activity currentActitity, final HttpRequest request, AsyncResponseListener callback) { sendRequest(currentActitity, request, callback, CONNECTION_TIMEOUT, SOCKET_TIMEOUT); } public static void sendRequest( final Activity currentActitity, final HttpRequest request, AsyncResponseListener callback, int timeoutConnection, int timeoutSocket) { InputHolder input = new InputHolder(request, callback); AsyncHttpSender sender = new AsyncHttpSender(); sender.execute(input); tasks.put(currentActitity, sender); } public static void cancelRequest(final Activity currentActitity){ if(tasks==null || tasks.size()==0) return; for (Activity key : tasks.keySet()) { if(currentActitity == key){ AsyncTask<?,?,?> task = tasks.get(key); if(task.getStatus()!=null && task.getStatus()!=AsyncTask.Status.FINISHED){ Log.i(TAG, "AsyncTask of " + task + " cancelled."); task.cancel(true); } tasks.remove(key); } } } public static synchronized HttpClient getClient() { if (httpClient == null){ //use following code to solve Adapter is detached error //refer: http://stackoverflow.com/questions/5317882/android-handling-back-button-during-asynctask BasicHttpParams params = new BasicHttpParams(); SchemeRegistry schemeRegistry = new SchemeRegistry(); schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); final SSLSocketFactory sslSocketFactory = SSLSocketFactory.getSocketFactory(); schemeRegistry.register(new Scheme("https", sslSocketFactory, 443)); // Set the timeout in milliseconds until a connection is established. HttpConnectionParams.setConnectionTimeout(params, CONNECTION_TIMEOUT); // Set the default socket timeout (SO_TIMEOUT) // in milliseconds which is the timeout for waiting for data. HttpConnectionParams.setSoTimeout(params, SOCKET_TIMEOUT); ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry); httpClient = new DefaultHttpClient(cm, params); } return httpClient; } }

然后是AsyncHttpSender。这里我用了InputHolder和OutputHolder来进行对象传递,简单包装了下:


Java代码
​​

​​​
​​​​​


1. /**
2. * AsyncHttpSender is the AsyncTask implementation
3. *
4. * @author bright_zheng
5. *
6. */
7. public class AsyncHttpSender extends AsyncTask<InputHolder, Void, OutputHolder> {
8. @Override
9. protected OutputHolder doInBackground(InputHolder... params) {
10. HttpEntity entity = null;
11. InputHolder input = params[0];
12. try {
13. HttpResponse response = AsyncHttpClient.getClient().execute((HttpUriRequest) input.getRequest());
14. StatusLine status = response.getStatusLine();
15. if(status.getStatusCode() >= 300) {
16. return new OutputHolder(
17. new HttpResponseException(status.getStatusCode(), status.getReasonPhrase()),
18. input.getResponseListener());
19. }
20. entity = response.getEntity();
21. Log.i(TAG, "isChunked:" + entity.isChunked());
22. if(entity != null) {
23. try{
24. entity = new BufferedHttpEntity(entity);
25. }catch(Exception e){
26. Log.e(<span style="background-color: rgb(255, 255, 255);">TAG</span>, e.getMessage(), e);
27. //ignore?
28. }
29. }
30. } catch (ClientProtocolException e) {
31. Log.e(<span style="background-color: rgb(255, 255, 255);">TAG</span>, e.getMessage(), e);
32. return new OutputHolder(e, input.getResponseListener());
33. } catch (IOException e) {
34. Log.e(<span style="background-color: rgb(255, 255, 255);">TAG</span>, e.getMessage(), e);
35. return new OutputHolder(e, input.getResponseListener());
36. }
37. return new OutputHolder(entity, input.getResponseListener());
38. }
39. @Override
40. protected void onPreExecute(){
41. Log.i(<span style="background-color: rgb(255, 255, 255);">TAG</span>, "AsyncHttpSender.onPreExecute()");
42. super.onPreExecute();
43. }
44. @Override
45. protected void onPostExecute(OutputHolder result) {
46. Log.i(<span style="background-color: rgb(255, 255, 255);">TAG</span>, "AsyncHttpSender.onPostExecute()");
47. super.onPostExecute(result);
48. if(isCancelled()){
49. Log.i(<span style="background-color: rgb(255, 255, 255);">TAG</span>, "AsyncHttpSender.onPostExecute(): isCancelled() is true");
50. return; //Canceled, do nothing
51. }
52. AsyncResponseListener listener = result.getResponseListener();
53. HttpEntity response = result.getResponse();
54. Throwable exception = result.getException();
55. if(response!=null){
56. Log.i(<span style="background-color: rgb(255, 255, 255);">TAG</span>, "AsyncHttpSender.onResponseReceived(response)");
57. listener.onResponseReceived(response);
58. }else{
59. Log.i(<span style="background-color: rgb(255, 255, 255);">TAG</span>, "AsyncHttpSender.onResponseReceived(exception)");
60. listener.onResponseReceived(exception);
61. }
62. }
63. @Override
64. protected void onCancelled(){
65. Log.i(<span style="background-color: rgb(255, 255, 255);">TAG</span>, "AsyncHttpSender.onCancelled()");
66. super.onCancelled();
67. //this.isCancelled = true;
68. }
69. }

/** * AsyncHttpSender is the AsyncTask implementation * * @author bright_zheng * */public class AsyncHttpSender extends AsyncTask<InputHolder, Void, OutputHolder> { @Override protected OutputHolder doInBackground(InputHolder... params) { HttpEntity entity = null; InputHolder input = params[0]; try { HttpResponse response = AsyncHttpClient.getClient().execute((HttpUriRequest) input.getRequest()); StatusLine status = response.getStatusLine(); if(status.getStatusCode() >= 300) { return new OutputHolder( new HttpResponseException(status.getStatusCode(), status.getReasonPhrase()), input.getResponseListener()); } entity = response.getEntity(); Log.i(TAG, "isChunked:" + entity.isChunked()); if(entity != null) { try{ entity = new BufferedHttpEntity(entity); }catch(Exception e){ Log.e(TAG, e.getMessage(), e); //ignore? } } } catch (ClientProtocolException e) { Log.e(TAG, e.getMessage(), e); return new OutputHolder(e, input.getResponseListener()); } catch (IOException e) { Log.e(TAG, e.getMessage(), e); return new OutputHolder(e, input.getResponseListener()); } return new OutputHolder(entity, input.getResponseListener()); } @Override protected void onPreExecute(){ Log.i(TAG, "AsyncHttpSender.onPreExecute()"); super.onPreExecute(); } @Override protected void onPostExecute(OutputHolder result) { Log.i(TAG, "AsyncHttpSender.onPostExecute()"); super.onPostExecute(result); if(isCancelled()){ Log.i(TAG, "AsyncHttpSender.onPostExecute(): isCancelled() is true"); return; //Canceled, do nothing } AsyncResponseListener listener = result.getResponseListener(); HttpEntity response = result.getResponse(); Throwable exception = result.getException(); if(response!=null){ Log.i(TAG, "AsyncHttpSender.onResponseReceived(response)"); listener.onResponseReceived(response); }else{ Log.i(TAG, "AsyncHttpSender.onResponseReceived(exception)"); listener.onResponseReceived(exception); } } @Override protected void onCancelled(){ Log.i(TAG, "AsyncHttpSender.onCancelled()"); super.onCancelled(); //this.isCancelled = true; }}


Java代码
​​

​​​
​​​​​


1. /**
2. * Input holder
3. *
4. * @author bright_zheng
5. *
6. */
7. public class InputHolder{
8. private HttpRequest request;
9. private AsyncResponseListener responseListener;
10. public InputHolder(HttpRequest request, AsyncResponseListener responseListener){
11. this.request = request;
12. this.responseListener = responseListener;
13. }
14. public HttpRequest getRequest() {
15. return request;
16. }
17. public AsyncResponseListener getResponseListener() {
18. return responseListener;
19. }
20. }

/** * Input holder * * @author bright_zheng * */public class InputHolder{ private HttpRequest request; private AsyncResponseListener responseListener; public InputHolder(HttpRequest request, AsyncResponseListener responseListener){ this.request = request; this.responseListener = responseListener; } public HttpRequest getRequest() { return request; } public AsyncResponseListener getResponseListener() { return responseListener; }}


Java代码
​​

​​​
​​​​​


1. public class OutputHolder{
2. private HttpEntity response;
3. private Throwable exception;
4. private AsyncResponseListener responseListener;
5. public OutputHolder(HttpEntity response, AsyncResponseListener responseListener){
6. this.response = response;
7. this.responseListener = responseListener;
8. }
9. public OutputHolder(Throwable exception, AsyncResponseListener responseListener){
10. this.exception = exception;
11. this.responseListener = responseListener;
12. }
13. public HttpEntity getResponse() {
14. return response;
15. }
16. public Throwable getException() {
17. return exception;
18. }
19. public AsyncResponseListener getResponseListener() {
20. return responseListener;
21. }
22. }

public class OutputHolder{ private HttpEntity response; private Throwable exception; private AsyncResponseListener responseListener; public OutputHolder(HttpEntity response, AsyncResponseListener responseListener){ this.response = response; this.responseListener = responseListener; } public OutputHolder(Throwable exception, AsyncResponseListener responseListener){ this.exception = exception; this.responseListener = responseListener; } public HttpEntity getResponse() { return response; } public Throwable getException() { return exception; } public AsyncResponseListener getResponseListener() { return responseListener; } }

再来看看我们的Call back接口定义, AsyncResponseListener.java:


Java代码
​​

​​​
​​​​​


1. /**
2. * The call back interface for
3. *
4. * @author bright_zheng
5. *
6. */
7. public interface AsyncResponseListener {
8. /** Handle successful response */
9. public void onResponseReceived(HttpEntity response);
10. /** Handle exception */
11. public void onResponseReceived(Throwable response);
12. }

/** * The call back interface for * * @author bright_zheng * */public interface AsyncResponseListener { /** Handle successful response */ public void onResponseReceived(HttpEntity response); /** Handle exception */ public void onResponseReceived(Throwable response);}

以及抽象Call back的实现,AbstractAsyncResponseListener.java:


Java代码
​​

​​​
​​​​​


1. /**
2. * Abstract Async Response Listener implementation
3. *
4. * Subclass should implement at lease two methods.
5. * 1. onSuccess() to handle the corresponding successful response object
6. * 2. onFailure() to handle the exception if any
7. *
8. * @author bright_zheng
9. *
10. */
11. public abstract class AbstractAsyncResponseListener implements AsyncResponseListener{
12. public static final int RESPONSE_TYPE_STRING = 1;
13. public static final int RESPONSE_TYPE_JSON_ARRAY = 2;
14. public static final int RESPONSE_TYPE_JSON_OBJECT = 3;
15. public static final int RESPONSE_TYPE_STREAM = 4;
16. private int responseType;
17. public AbstractAsyncResponseListener(){
18. this.responseType = RESPONSE_TYPE_STRING; // default type
19. }
20. public AbstractAsyncResponseListener(int responseType){
21. this.responseType = responseType;
22. }
23. public void onResponseReceived(HttpEntity response){
24. try {
25. switch(this.responseType){
26. case RESPONSE_TYPE_JSON_ARRAY:{
27. String responseBody = EntityUtils.toString(response);
28. Log.i(<span style="background-color: rgb(255, 255, 255);">TAG</span>, "Return JSON String: " + responseBody);
29. JSONArray json = null;
30. if(responseBody!=null && responseBody.trim().length()>0){
31. json = (JSONArray) new JSONTokener(responseBody).nextValue();
32. }
33. onSuccess(json);
34. break;
35. }
36. case RESPONSE_TYPE_JSON_OBJECT:{
37. String responseBody = EntityUtils.toString(response);
38. Log.i(<span style="background-color: rgb(255, 255, 255);">TAG</span>, "Return JSON String: " + responseBody);
39. JSONObject json = null;
40. if(responseBody!=null && responseBody.trim().length()>0){
41. json = (JSONObject) new JSONTokener(responseBody).nextValue();
42. }
43. onSuccess(json);
44. break;
45. }
46. case RESPONSE_TYPE_STREAM:{
47. onSuccess(response.getContent());
48. break;
49. }
50. default:{
51. String responseBody = EntityUtils.toString(response);
52. onSuccess(responseBody);
53. }
54. }
55. } catch(IOException e) {
56. onFailure(e);
57. } catch (JSONException e) {
58. onFailure(e);
59. }
60. }
61. public void onResponseReceived(Throwable response){
62. onFailure(response);
63. }
64. protected void onSuccess(JSONArray response){}
65. protected void onSuccess(JSONObject response){}
66. protected void onSuccess(InputStream response){}
67. protected void onSuccess(String response) {}
68. protected void onFailure(Throwable e) {}
69. }

/** * Abstract Async Response Listener implementation * * Subclass should implement at lease two methods. * 1. onSuccess() to handle the corresponding successful response object * 2. onFailure() to handle the exception if any * * @author bright_zheng * */public abstract class AbstractAsyncResponseListener implements AsyncResponseListener{ public static final int RESPONSE_TYPE_STRING = 1; public static final int RESPONSE_TYPE_JSON_ARRAY = 2; public static final int RESPONSE_TYPE_JSON_OBJECT = 3; public static final int RESPONSE_TYPE_STREAM = 4; private int responseType; public AbstractAsyncResponseListener(){ this.responseType = RESPONSE_TYPE_STRING; // default type } public AbstractAsyncResponseListener(int responseType){ this.responseType = responseType; } public void onResponseReceived(HttpEntity response){ try { switch(this.responseType){ case RESPONSE_TYPE_JSON_ARRAY:{ String responseBody = EntityUtils.toString(response); Log.i(TAG, "Return JSON String: " + responseBody); JSONArray json = null; if(responseBody!=null && responseBody.trim().length()>0){ json = (JSONArray) new JSONTokener(responseBody).nextValue(); } onSuccess(json); break; } case RESPONSE_TYPE_JSON_OBJECT:{ String responseBody = EntityUtils.toString(response); Log.i(TAG, "Return JSON String: " + responseBody); JSONObject json = null; if(responseBody!=null && responseBody.trim().length()>0){ json = (JSONObject) new JSONTokener(responseBody).nextValue(); } onSuccess(json); break; } case RESPONSE_TYPE_STREAM:{ onSuccess(response.getContent()); break; } default:{ String responseBody = EntityUtils.toString(response); onSuccess(responseBody); } } } catch(IOException e) { onFailure(e); } catch (JSONException e) { onFailure(e); } } public void onResponseReceived(Throwable response){ onFailure(response); } protected void onSuccess(JSONArray response){} protected void onSuccess(JSONObject response){} protected void onSuccess(InputStream response){} protected void onSuccess(String response) {} protected void onFailure(Throwable e) {}}

这样我们使用起来就非常清晰、简单了。
下面贴个简单的客户端用法代码片段:
1、这个是把服务器端响应当stream用的,用以诸如文件、图片下载之类的场景:


Java代码
​​

​​​
​​​​​


1. AsyncHttpClient.sendRequest(this, request,
2. new AbstractAsyncResponseListener(AbstractAsyncResponseListener.RESPONSE_TYPE_STREAM){
3. @Override
4. protected void onSuccess(InputStream response){
5. Bitmap bmp = null;
6. try {
7. //bmp = decodeFile(response, _facial.getWidth());
8. bmp = BitmapFactory.decodeStream(response);
9. //resize to fit screen
10. bmp = resizeImage(bmp, _facial.getWidth(), true);
11. candidateCache.put(candidate_id, bmp);
12. ((ImageView) v).setImageBitmap(bmp);
13. dialog.dismiss();
14. } catch (Exception e) {
15. onFailure(e);
16. }
17. }
18. @Override
19. protected void onFailure(Throwable e) {
20. Log.i(TAG, "Error: " + e.getMessage(), e);
21. updateErrorMessage(e);
22. dialog.dismiss();
23. }
24. });

AsyncHttpClient.sendRequest(this, request, new AbstractAsyncResponseListener(AbstractAsyncResponseListener.RESPONSE_TYPE_STREAM){ @Override protected void onSuccess(InputStream response){ Bitmap bmp = null; try { //bmp = decodeFile(response, _facial.getWidth()); bmp = BitmapFactory.decodeStream(response); //resize to fit screen bmp = resizeImage(bmp, _facial.getWidth(), true); candidateCache.put(candidate_id, bmp); ((ImageView) v).setImageBitmap(bmp); dialog.dismiss(); } catch (Exception e) { onFailure(e); } } @Override protected void onFailure(Throwable e) { Log.i(TAG, "Error: " + e.getMessage(), e); updateErrorMessage(e); dialog.dismiss(); } });

2、这个是把服务器端响应当JSON用的,用以诸如获取基本文本信息之类的场景:


Java代码
​​

​​​
​​​​​


1. // Async mode to get hit result
2. AsyncHttpClient.sendRequest(this, request,
3. new AbstractAsyncResponseListener(AbstractAsyncResponseListener.RESPONSE_TYPE_JSON_ARRAY){
4. @Override
5. protected void onSuccess(JSONArray response){
6. Log.i(TAG, "UploadAndMatch.onSuccess()...");
7. candidates = response;
8. if(candidates!=null && candidates.length()>0){
9. hit_count = candidates.length();
10. Log.i(TAG, "HIT: " + hit_count);
11. updateStatus(String.format(context.getString(R.string.msg_got_hit), hit_count));
12. //update UI
13. refreshCurrentUI(1);
14. }else{
15. Log.i(TAG, "No HIT!");
16. updateStatus(context.getString(R.string.msg_no_hit));
17. //update UI
18. refreshCurrentUI(0);
19. }
20. }
21. @Override
22. protected void onFailure(Throwable e) {
23. Log.e(TAG, "UploadAndMatch.onFailure(), error: " + e.getMessage(), e);
24. updateErrorMessage(e);
25. //update UI
26. refreshCurrentUI(-1);
27. }
28. });

标签:Log,void,response,TAG,Asynchronous,new,Android,public,HTTPClient
From: https://blog.51cto.com/jdsjlzx/5733506

相关文章

  • Android GridView控件自定义
    虽然​​Android​​​已自带了GridView,但是,却不够灵活,同时也不能自由添加控件,因此,本人通过需要进一步封装,来实现​​Android自定义GridView控件​​,达到自己需要的效果。......
  • Android实现渐显按钮的左右滑动效果
    本示例演示在Android中实现带渐显按钮的左右滑动效果。关于滑动效果,在我的上一篇博文中提到过,有兴趣的朋友可以访问如果大家想实现带指引效果的左右滑动,请访问博先看下......
  • Android闪屏示例程序
     用过手机QQ的基本上都知道,刚启动程序时候会在一个界面停留一会,按任意键的就直接跳过,这就是所谓的闪屏。那么,在Android中怎样实现这样的效果呢? 1、新建一个Android项目,命......
  • Android实现图片倒影效果
    ​​android倒影实现抖动的镜面效果​​​​http://clareshao.iteye.com/blog/1419695​​android中的gallery的一个样式,具有倒影效果。左右滑动也不错。​​http://down......
  • Android开发--构建项目安装包APK(debug版)
    1.build→BuildAPK(s),点击即可构建2.点击日志可以查看构建情况3.点击locate即可进入debug文件夹4.也可以在构建完成后直接按照路径找到debug文件夹其中apk文件即所需安装......
  • Android类加载流程
    背景由于前前前阵子写了个壳,得去了解类的加载流程,当时记了一些潦草的笔记。这几天把这些东西简单梳理了一下,本文分析的代码基于Android8.1.0源码。流程分析从loadClass......
  • Tubian Linux 0.45,兼容Windows和Android的国产Linux系统!
    Github主页(提供下载):https://github.com/jinshulumengchuang/Tubian-Linux123网盘下载:https://www.123pan.com/s/XjkKVv-JO9Uvhttps://www.123pan.com/s/XjkKVv-BO9Uvhtt......
  • 关于Android开发工具的下载之ADT篇
    ADT的下载首先可以选择下面推荐的两个网站去下载相应的安装包,网址如下:http://tools.android-studio.org/index.php/adt-bundle-plugin或者http://www.androiddevtools.......
  • 面向初学者的 Android 应用开发基础知识
    Android是一个基本上为手机构建的操作系统。它基于LinuxKernel和其他开源软件,由Google开发。它用于智能手机和平板电脑等触摸屏移动设备。但现在这些都用于AndroidAuto......
  • Android系统10 RK3399 init进程启动(四十) 开机自启动脚本init.rc执行逻辑框架
    说明系统:Android10.0设备:FireFlyRK3399(ROC-RK3399-PC-PLUS)前言这个章节我们开始学习新的知识点,init.rc相关概念,也就是Android开机自启动的脚本,这个脚本能启动shell脚......