1. 程式人生 > >【一步一個腳印】Tomcat+MySQL為自己的APP打造伺服器(3-1)Android 和 Service 的互動之GET方式

【一步一個腳印】Tomcat+MySQL為自己的APP打造伺服器(3-1)Android 和 Service 的互動之GET方式

      好久沒更新了,罪過罪過。最對不起的人莫過於那些支援和等待在下拙文的諸位,在此道一聲抱歉。管窺之見,僥倖博得各位認同,給了我莫大的鼓勵。

      話休絮煩,文接前章。

      到【一步一個腳印】Tomcat+MySQL為自己的APP打造伺服器(2-3)Servlet連線MySQL資料庫為止,我們已經將服務端的部分走通了:通過 Servlet 連線 MySQL ,分析業務需求進行響應的增刪改查操作返回對應的處理結果。(上一篇結尾是說接下來該說POST請求了,但是在準備這篇文章時發現POST再推後一篇,等我們把 Android 通過 GET 方式和 Servlet 伺服器互動全部走完了,回過頭來對比著說 POST 會更加明瞭,所以決定修正一下之前的思路,本章我們繼續完成 GET 的剩下內容)

      很明顯,想要 Android 和伺服器進行互動,必然要使用到網路,為了解決後顧之憂,我們先下手為強,在 Manifest 檔案中宣告網路訪問許可權

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

      這個許可權可不是平白無故就去申請的,因為我們要通過網路和伺服器互動,要完成這一互動過程,就要用到 Android 網路技術。Android 網路技術包含目前所有主流網路技術,比如你聽過的TCP/IP(Socket、ServiceSocket)、UDP... ...(媽的,不寫了。講真,網路這塊其實我已經不懂了,曾經真的懂過,反正大學時候網路基礎學的挺嗨,幾年不接觸已經恍如隔世了。以免誤人子弟,或者是遇到真正的大神被拆穿就尷尬了大笑

)。我們最常用的應該算是 HTTP 和 WebView 了,這裡就以最常用的 HTTP 通訊為例來說明:

      在 Android 上傳送 HTTP 請求的方式一般有兩種:HttpURLConnectionHttpClient,我們都來試用一下:

(一)HttpURLConnection 進行 HTTP 請求

      先是 HttpURLConnection,直接上程式碼吧,用法有註釋:

public class HttpURLConActivity extends AppCompatActivity {

    private TextView tvContent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_http_urlcon);

        tvContent = (TextView) findViewById(R.id.tv_content); // 這裡頁面上就一個簡單的TextView,用於展示獲取到報文內容
        requestUsingHttpURLConnection();
    }

    private void requestUsingHttpURLConnection() {
        // 網路通訊屬於典型的耗時操作,開啟新執行緒進行網路請求
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection = null;
                try {
                    URL url = new URL("https://www.baidu.com"); // 宣告一個URL,注意——如果用百度首頁實驗,請使用https
                    connection = (HttpURLConnection) url.openConnection(); // 開啟該URL連線
                    connection.setRequestMethod("GET"); // 設定請求方法,“POST或GET”,我們這裡用GET,在說到POST的時候再用POST
                    connection.setConnectTimeout(8000); // 設定連線建立的超時時間
                    connection.setReadTimeout(8000); // 設定網路報文收發超時時間
                    InputStream in = connection.getInputStream();  // 通過連線的輸入流獲取下發報文,然後就是Java的流處理
                    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                    StringBuilder response = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null){
                        response.append(line);
                    }

                    tvContent.setText(response.toString()); // 地雷
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
      Run,Fuck!報錯——

      子執行緒操作UI報錯

        典型的子執行緒試圖操作 UI 元素報錯,為啥,因為網路請求是在新開的子執行緒中執行,當然不能直接拿到結果就給 TextView 賦值了!怎麼做?Android 的Handler訊息機制這不就用上了嘛!

    /**
     * 訊息處理
     */
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            if(msg.what == 1){
                tvContent.setText(msg.obj.toString());
            }
        }
    };

    private void requestUsingHttpURLConnection() {
        ......
        /* 獲取返回報文部分省略,將原來
         * tvContent.setText(response.toString())替換為
         * 給handler傳送訊息
         */
        Message msg = new Message();
        msg.what = 1;
        msg.obj = response.toString();
        Log.e("WangJ", response.toString());
        handler.sendMessage(msg);
        ......
    }
        重新 Run,結果

        百度首頁報文

      什麼?看不懂,什麼鬼!其實伺服器返回的百度首頁就是這樣的 HTML 程式碼,只是平時我們使用瀏覽器開啟的時候,瀏覽器引擎幫我們把這些程式碼解析和展示成了花花綠綠的頁面,僅此而已。

(二)HttpClient 進行 HTTP 請求

      HttpClient 是Apache 提供的 HTTP 網路訪問介面,但是原生 Android 系統內建了這套藉口,所以不用引入第三方 jar 就可以直接用。他可以和 HttpURLConnection 完成幾乎一模一樣的效果,但是兩者的使用方法還是有一些區別的。下面我們用程式碼來說明:

public class HttpClientActivity extends AppCompatActivity {
    private TextView tvContent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_http_client);

        tvContent = (TextView) findViewById(R.id.tv_content);
        requestUsingHttpClient();
    }

    // 同樣的訊息機制
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == 1) {
                tvContent.setText(msg.obj.toString());
            }
        }
    };

    private void requestUsingHttpClient() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpClient client = new DefaultHttpClient(); // HttpClient 是一個介面,無法例項化,所以我們通常會建立一個DefaultHttpClient例項
                HttpGet get = new HttpGet("https://www.baidu.com"); // 發起GET請求就使用HttpGet,發起POST請求則使用HttpPost,這裡我們先使用HttpGet
                try {
                    HttpResponse httpResponse = client.execute(get); // 呼叫HttpClient物件的execute()方法
                    // 狀態碼200說明響應成功
                    if (httpResponse.getStatusLine().getStatusCode() == 200) {
                        HttpEntity entity = httpResponse.getEntity(); // 取出報文的具體內容
                        String response = EntityUtils.toString(entity, "utf-8"); // 報文編碼

                        // 傳送訊息
                        Message msg = new Message();
                        msg.what = 1;
                        msg.obj = response;
                        handler.sendMessage(msg);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

        怎麼樣,還是挺簡潔的吧!Run,和前一個圖一樣,節省篇幅圖就不貼了。

(三)HttpClient 的窘境

      年輕人,是不是要到問題了偷笑(沒遇到問題的請自覺忽略,如果你用的 Android Studio比較新,compileSdkVersion >= 23,相信你會遇到的)?是不是在寫程式碼中找不到 HttpClient 類?那就對了!因為從 Android 6.0(API 23) 往後 Google 又把 HttpClient 給幹掉了,為什麼?說是因為它介面、方法太多,API太過複雜,升級維護難以在當前版本API上進行,這就會導致 Android 版本相容上出現難以解決的問題,所以就把它幹掉了,因為使用 HttpURLConnection 也能達到同樣的效果,並且易於維護。囉嗦個屁呀,問題咋解決呢?改 SDK 版本唄,讓他SDK <= 22 就可以了。什麼!業務不允許?要求最新版 SDK?別怕,到 Apache 下載最新 jar 包匯入工程,還像以前一樣用,不過方法名可能不一樣了。

      就這樣,Android 傳送 HTTP 請求就完成了。什麼?訊息處理機制太麻煩了?是的!我也舉得麻煩,其實 Android 官方也覺得麻煩,所以 Android 為了降低這個開發難度,提供了AsyncTask。AsyncTask就是一個封裝過的後臺任務類,顧名思義就是非同步任務,其實現原理也是基於非同步訊息處理機制,只是 Android給我們做了很好的封裝而已,相對於 Handler 更輕量,適用於簡單的非同步處理,但是在面對多個非同步任務更新同一個或同一組 UI 時的同步就比較困難,不瞭解不要緊,以後用用就知道問題在哪了,一口也吃不成個大胖子。下面我們在 http 請求時就用AsyncTask來處理吧——

(四)Android 和 Servlet 伺服器通過 HTTP GET 模式進行互動

      來吧,來到了今天的主題。首先,請確保你的 Tomcat 上部署的 Servlet 已經啟動,確保資料庫服務正常啟動並且資料庫連線正常,有問題請參考之前的 【一步一個腳印】Tomcat+MySQL為自己的APP打造伺服器

      (雙12換了電腦,環境都是新裝的,如與之前的資料不符,請以自己的為準

      資料庫表就是這麼一個簡單的表

        資料庫表結構

      下邊是伺服器Servlet的程式碼,其實和之前文章中的程式碼原理上一模一樣,但是為了寫一個完整的互動,我這裡重寫了一個:

      處理“註冊”邏輯的Servlet:

@WebServlet(description = "註冊使用的Servlet", urlPatterns = { "/RegisterServlet" })
public class RegisterServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * Default constructor.
	 */
	public RegisterServlet() {
		LogUtil.log("RegisterServlet construct...");
	}

	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String method = request.getMethod();
		if ("GET".equals(method)) {
			LogUtil.log("請求方法:GET");
			doGet(request, response);
		} else if ("POST".equals(method)) {
			LogUtil.log("請求方法:POST");
			doPost(request, response);
		} else {
			LogUtil.log("請求方法分辨失敗!");
		}
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String code = "";
		String message = "";

		String account = request.getParameter("account");
		String password = request.getParameter("password");
		LogUtil.log(account + ";" + password);

		Connection connect = DatabaseUtil.getConnection();
		try {
			Statement statement = connect.createStatement();
			String sql = "select account from " + DatabaseUtil.Table_Account + " where account='" + account + "'";
			LogUtil.log(sql);
			ResultSet result = statement.executeQuery(sql);
			if (result.next()) { // 能查到該賬號,說明已經註冊過了
				code = "100";
				message = "該賬號已存在";
			} else {
				String sqlInsert = "insert into " + DatabaseUtil.Table_Account + "(account, password) values('"
						+ account + "', '" + password + "')";
				LogUtil.log(sqlInsert);
				if (statement.executeUpdate(sqlInsert) > 0) { // 否則進行註冊邏輯,插入新賬號密碼到資料庫
					code = "200";
					message = "註冊成功";
				} else {
					code = "300";
					message = "註冊失敗";
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}

		response.getWriter().append("code:").append(code).append(";message:").append(message);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

	}

	@Override
	public void destroy() {
		LogUtil.log("RegisterServlet destory.");
		super.destroy();
	}

}
      處理“登入”邏輯的Servlet:
@WebServlet(description = "登入", urlPatterns = { "/LoginServlet" })
public class LoginServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public LoginServlet() {
		super();
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String code = "";
		String message = "";

		String account = request.getParameter("account");
		String password = request.getParameter("password");
		LogUtil.log(account + ";" + password);

		Connection connect = DatabaseUtil.getConnection();
		try {
			Statement statement = connect.createStatement();
			String sql = "select account from " + DatabaseUtil.Table_Account + " where account='" + account
					+ "' and password='" + password + "'";
			LogUtil.log(sql);
			ResultSet result = statement.executeQuery(sql);
			if (result.next()) { // 能查到該賬號,說明已經註冊過了
				code = "200";
				message = "登陸成功";
			} else {

				code = "100";
				message = "登入失敗,密碼不匹配或賬號未註冊";
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}

		response.getWriter().append("code:").append(code).append(";message:").append(message);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		LogUtil.log("不支援POST方法");
	}

}
      /*請求和響應編碼格式設定資料庫連線程式碼和之前的一樣,這裡就不重複貼了 */

     接下來是Android客戶端的程式碼:

     常量類

public class Constant {
    public static String URL = "http://192.168.1.109:8080/FirstServletService/"; // IP地址請改為你自己的IP

    public static String URL_Register = URL + "RegisterServlet";
    public static String URL_Login = URL + "LoginServlet";
}
      Activity的介面
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="@dimen/activity_vertical_margin">

    <EditText
        android:id="@+id/et_account"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="請輸入賬號" />

    <EditText
        android:id="@+id/et_password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="請輸入登入密碼"
        android:inputType="textPassword" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn_register"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Register" />

        <Button
            android:id="@+id/btn_login"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Login" />

    </LinearLayout>

    <!-- 用來顯示報文返回結果 -->
    <TextView
        android:id="@+id/tv_result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>
      Activity的程式碼
public class MainActivity extends Activity {

    private EditText etAccount;
    private EditText etPassword;
    private TextView tvResult;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        etAccount = (EditText) findViewById(R.id.et_account);
        etPassword = (EditText) findViewById(R.id.et_password);
        tvResult = (TextView) findViewById(R.id.tv_result);

        Button btnRegister = (Button) findViewById(R.id.btn_register);
        btnRegister.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!StringUtil.isEmpty(etAccount.getText().toString())
                        && !StringUtil.isEmpty(etPassword.getText().toString())) {
                    Log.e("WangJ", "都不空");
                    register(etAccount.getText().toString(), etPassword.getText().toString());
                } else {
                    Toast.makeText(MainActivity.this, "賬號、密碼都不能為空!", Toast.LENGTH_SHORT).show();
                }
            }
        });

        Button btnLogin = (Button) findViewById(R.id.btn_login);
        btnLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!StringUtil.isEmpty(etAccount.getText().toString())
                        && !StringUtil.isEmpty(etPassword.getText().toString())) {
                    Log.e("WangJ", "都不空");
                    login(etAccount.getText().toString(), etPassword.getText().toString());
                } else {
                    Toast.makeText(MainActivity.this, "賬號、密碼都不能為空!", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }

    private void register(String account, String password) {
        String registerUrlStr = Constant.URL_Register + "?account=" + account + "&password=" + password;
        new MyAsyncTask(tvResult).execute(registerUrlStr);
    }

    private void login(String account, String password) {
        String registerUrlStr = Constant.URL_Login + "?account=" + account + "&password=" + password;
        new MyAsyncTask(tvResult).execute(registerUrlStr);
    }

    /**
     * AsyncTask類的三個泛型引數:
     * (1)Param 在執行AsyncTask是需要傳入的引數,可用於後臺任務中使用
     * (2)後臺任務執行過程中,如果需要在UI上先是當前任務進度,則使用這裡指定的泛型作為進度單位
     * (3)任務執行完畢後,如果需要對結果進行返回,則這裡指定返回的資料型別
     */
    public static class MyAsyncTask extends AsyncTask<String, Integer, String> {

        private TextView tv; // 舉例一個UI元素,後邊會用到

        public MyAsyncTask(TextView v) {
            tv = v;
        }

        @Override
        protected void onPreExecute() {
            Log.w("WangJ", "task onPreExecute()");
        }

        /**
         * @param params 這裡的params是一個數組,即AsyncTask在啟用執行是呼叫execute()方法傳入的引數
         */
        @Override
        protected String doInBackground(String... params) {
            Log.w("WangJ", "task doInBackground()");
            HttpURLConnection connection = null;
            StringBuilder response = new StringBuilder();
            try {
                URL url = new URL(params[0]); // 宣告一個URL,注意如果用百度首頁實驗,請使用https開頭,否則獲取不到返回報文
                connection = (HttpURLConnection) url.openConnection(); // 開啟該URL連線
                connection.setRequestMethod("GET"); // 設定請求方法,“POST或GET”,我們這裡用GET,在說到POST的時候再用POST
                connection.setConnectTimeout(80000); // 設定連線建立的超時時間
                connection.setReadTimeout(80000); // 設定網路報文收發超時時間
                InputStream in = connection.getInputStream();  // 通過連線的輸入流獲取下發報文,然後就是Java的流處理
                BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                String line;
                while ((line = reader.readLine()) != null) {
                    response.append(line);
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return response.toString(); // 這裡返回的結果就作為onPostExecute方法的入參
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            // 如果在doInBackground方法,那麼就會立刻執行本方法
            // 本方法在UI執行緒中執行,可以更新UI元素,典型的就是更新進度條進度,一般是在下載時候使用
        }

        /**
         * 執行在UI執行緒中,所以可以直接操作UI元素
         * @param s
         */
        @Override
        protected void onPostExecute(String s) {
            Log.w("WangJ", "task onPostExecute()");
            tv.setText(s);
        }

    }
}
      程式碼很簡單,沒什麼解釋的。本文的主要內容是將資料庫、伺服器、Android串聯起來這一過程。

      *注意* 這裡我們不可能通過行動網路來連線我們的伺服器,因為我們的伺服器部署在本機本地,沒有公網IP,所以這裡我們用自己的電腦開啟一個共享熱點,然後用手機連上這個熱點來進行訪問本機伺服器,IP地址通過ipconfig命令檢視。開啟網路熱點自己百度吧,命令列不行直接找360免費WIFI等等,這篇已經夠囉嗦了,就不再加入其他干擾內容了,請關注本文的重點。

      執行前再檢查一遍:(1)資料庫連線正常(2)伺服器執行正常(3)Android端訪問的本機伺服器地址可連通。然後Run,看結果

        執行結果

      就這樣就完事了,其實篇幅不短,內容卻不多。到此GET方式的互動就完成了,同理,POST互動也是依葫蘆畫瓢,下一篇我們就來說說POST方式的互動。

      佶屈聱牙,作拋磚引玉之用,水平有限,如有不足歡迎留言指正!

相關推薦

一個腳印Tomcat+MySQL自己APP打造伺服器1伺服器環境搭建

做 Android 開發一年多了,雖然不敢說有多精通,但也相對熟悉。做久了就會發現 Android 在行外人眼中是多麼高深(包括 IOS 也一樣),但是我們自己知道其實 Android 和 Web 前

一個腳印Tomcat+MySQL自己APP打造伺服器3-1Android Service互動GET方式

      好久沒更新了,罪過罪過。最對不起的人莫過於那些支援和等待在下拙文的諸位,在此道一聲抱歉。管窺之見,僥倖博得各位認同,給了我莫大的鼓勵。       話休絮煩,文接前章。       到【一步一個腳印】Tomcat+MySQL為自己的APP打造伺服器(2-3)Se

一個腳印Tomcat+MySQL自己APP打造伺服器3-2Android Service互動POST方式

        今天是聖誕節,雖說我本人對這個西方節日沒什麼感覺,但畢竟還是有很多小年輕人(自認為已然脫離年輕人的航道)挺在意這個節日的,在這裡祝大家聖誕快樂吧(要是湊巧你也沒什麼感覺,那就預祝元旦快

一個腳印Tomcat+MySQL自己APP打造伺服器4完結篇

        在這個系列的前幾篇文章中,從最初簡單的伺服器環境搭建、MySQL資料庫的安裝、Servlet 的原理及使用、資料庫的連線及CURD操作、Android和伺服器GET/POST資料互動,到最後JSon格式報文的使用,我們已經將這個過程完整的走完一遍,但是其中

安卓-自定義佈局安卓App開發思路 一個腳印實現內嵌在app中的webview 騰訊開源X5 高效安全

實現內嵌在app中的webview 採用騰訊開源X5 高效安全 webview在app的使用中,十分頻繁,原生的webview載入速度相對來說很慢,而且很費流量。騰訊開源了x5的webview

安卓-自定義佈局安卓App開發思路 一個腳印實現自定義滾動的新聞條目上下滾動-仿蘑菇街

實現自定義滾動的新聞條目上下滾動-仿蘑菇街       這種上下滾動的自定義佈局,就像是公告那種上下的翻滾,一般為文字的滾動,很明顯,就是自定義佈局,一般是線性佈局。這裡提到的安卓原生的控制元件自然是

紮紮實實把基礎打牢,一個腳印

    敢於把自己當做一個較笨的人,不強求自己做到完美,不要認為自己很牛逼。 紮紮實實把基礎打牢,一步一個腳印,不要急躁,比什麼都靠譜。 Stay hungry. Stay foolish. 敢於把自己當做一個較笨的人,不強求自己做到完美,不要

哪有什麼天生王者,不過是一個腳印

轉載自公眾號java團長 前言 Tomcat,這隻3腳貓,大學的時候就認識了,直到現在工作中,也常會和它打交道。這是一隻神奇的貓,今天讓我來抽象你,實現你! Tomcat Write MyTomcat Tomcat是非常流行的Web Server,它還是一個

一個腳印,QAD助力CAPP走出資訊化進階

【本文轉載於e-works數字化企業網】 客戶引言: “隨著汽車市場進入拐點,整個行業尤其是零部件廠商無可避免的將從管理入手進行轉型升級。QAD ERP解決方案在汽車行業擁有“專業+領先”的能力與實踐積累,“快速+便捷”的實施模式,非常適合基礎薄弱並且快速發展的中國民企。” ---長春市

一個腳印筆試面試—google2013年校園招聘筆試題答案

  (注:答案全部自己個人,希望指正討論)   1.單項選擇題 1.1    使用C語言將一個1G位元組的字元陣列從頭到尾全部設定為字元'A',在一臺典型的當代PC上,需要花費的CPU時間的數量級最接近:     &

一個腳印的往前走!

  想想自己曾經學習C語言時,初次見到指標、地址,只能死記硬背,經過一段時間的軟磨硬泡,終於有所收穫,在此記錄自己對C語言中地址、指標的理解。   推薦對C語言有一定理解的程式設計師閱讀。   學習過C語言的程式設計師們,一定都知道“指標就是地址”的經典描述

LeetcodeDP-二維陣列 63. Unique Paths II / 不同路徑2帶障礙

給定一個二維陣列,每格為0/1值,1代表無法通過。求從左上到右下的不同路徑數。只能往右/下走。 Input: [   [0,0,0],   [0,1,0],   [0,0,0] ] Output: 2 Explanation: There is one obstacl

杭電100題RPG專場練習賽 2063 過山車匈牙利演算法

Problem Description 過山車的每一排只有兩個座位,每個女生必須找個男生做partner和她同坐,每個女生都願意跟若干男生做partner。只讓找到partner的人去坐過山車,最多有多少對組合可以坐上過山車? Input 輸入資料的第一行是三個整數K

教你寫股票走勢圖——K線圖二圖表聯動

K線圖越做發現坑越多,跟之前做的分時圖完全不是一個重量級的啊,分時圖不需要滾動,少走了很多彎路,K線圖因為滾動的問題,會導致很多其他問題,比如: 多個圖表之間滾動時怎麼聯動 高亮滾動衝突 放縮聯動 … 表對齊 下面我們就開始介紹本

Linux Device Driver3.1—ioctl——程式碼

《Linux Device Driver》這本書的卻做的很好,對於一個初學者來說雖然有點難度,但是隻要認真看,絕對是大有裨益的! 好了,昨天把ioctl的原理以及涉及到的程式碼貼了一下,今天就做了做實驗,感覺還湊合,所以就貼出來!對自己也算是做個筆記吧! 今天這個實驗主

Linux Device Driver3.1—ioctl——原理

大部分驅動除了需要具備讀寫裝置能力外,還需要具備對硬體控制的能力,例如:要求裝置報告錯誤資訊改變模特率,這些操作常常通過ioctl方法來實現! 這裡的東西看上去的卻挺多,但是還是依照此次的原則,只是對自己知識的一個複習,所以也就懶得貼那麼多的文字。 1、ioctl方法

編程訓練-PATA1135 Is It A Red-Black Tree 30 分

watermark per inpu sea rate ifdef mark pre avl 1135 Is It A Red-Black Tree (30 分) There is a kind of balanced binary search tree named re

3.1一個按鍵所能涉及的:按鍵中斷

/* AUTHOR: Pinus * Creat on : 2018-10-11 * KERNEL : linux-4.4.145 * BOARD : JZ2440(arm9 s3c2440) * REFS : 韋東山視訊教程第二期 */ 概述         

linux下 mysql 5.7 配置 my.cnfmysqld.cnf檔案位置 以及具體的配置方式

一、問題 mysql 5.7 版本,/etc/my.cnf  和 /etc/mysql/my.cnf  空空如也,需要自己新增需要的配置,而不能像之前一樣 只要去掉 #號註釋即可。 可以參考djCode的blogMySQL的my.cnf檔案(解決5.7.18下沒有my-d

學習VBAExcel VBA 在當前目錄建立一個excel表

首先我們新建一個EXcel表,然後調用出Visual Basic,同時寫入程式碼: Sub AddNew() Dim path As String, filepath As String filepa