APP Implementation of Film Ticket Purchase (3)-Android Client

Keywords: Android Database network github

Android Client for FOE Film Ticket Purchase APP


_finally came to the end of this series of learning, this time, I will work with you to make a simple Android APP, to achieve access to the database through the server.

Do you remember the demo of the last blog that gave you a spoiler ahead of time? Don't forget it. I'll play it again.

Firstly, the Android development tool I use is Android Studio. Readers of Eclispe, you can just read the code.

I'm not going to say how to configure JDK, ADT and so on, including layout of layout files, even the knowledge of listView, adapter and so on. By default, you all have simple Android development. Ha-ha. My focus on this blog is how to build a connection and access the server to get the data we want.

First of all, the login function of the first page. We give the login button a listening event.

        Button btnLogin = (Button)findViewById(R.id.ButtonLogin);//Get the login button
        btnLogin.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                String usernmae = etUsername.getText().toString();
                String password = etPassword.getText().toString();
                if (usernmae.isEmpty()) {
                    Toast.makeText(MainActivity.this, "User name is empty", Toast.LENGTH_SHORT).show();
                } else if (password.isEmpty()) {
                    Toast.makeText(MainActivity.this, "The password is empty", Toast.LENGTH_SHORT).show();
                } else { 
                    Login(usernmae, password); //Execute the Login function if the username and password are not empty.
                }
            }
        });

_Here is to consolidate the knowledge that Internet access in Android development can not be executed in the main thread. In fact, many other developments are the same, because it takes time to access the Internet, downloading resources and so on can easily block the main thread, like Uinty, but also in the process. In Android, there are also some ways to give us simple new threads and interact with the interface. Among them, I used AsyncTask this time.

Let's look at the Login function.

    private void Login(String username, String password) {
        String loginUrl = LoginURL + "?Username=" + username + "&Password=" + password;
        new MyAsyncTask(MainActivity.this, username).execute(loginUrl);
    }

It's very simple. Oh, by the way, you remember to apply for network privileges in manifest.

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

In retrospect, our Login function is to construct an instance of MyAyncTask using the context of our MainActivity and username as constructor parameters of MyAyncTask, and then execute the execyte(loginUrl).

Now let's look at our MyAyncTask class

    public static class MyAsyncTask extends AsyncTask<String, Integer, String> {
        private Context context;
        private String uName;

        public  MyAsyncTask(Context context, String username) {
            this.context = context;
            this.uName = username;
        }

        @Override
        protected void onPreExecute() {

        }

        @Override
        protected  String doInBackground(String... params) {
            HttpURLConnection connection = null;
            StringBuilder response = new StringBuilder();
            try {
                URL url = new URL(params[0]);
                connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("GET");
                connection.setConnectTimeout(8000);
                connection.setReadTimeout(8000);
                InputStream in = connection.getInputStream();
                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();
        }

        @Override
        protected  void  onProgressUpdate(Integer... Values) {

        }

        @Override
        protected void onPostExecute(String s) {
            String text = s.substring(s.indexOf("resMsg=")+7);
            Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
            if ("Successful login}".equals(text)) {
                SharedPreferences userSharePreferences = context.getSharedPreferences("userInfo", Activity.MODE_PRIVATE);
                SharedPreferences.Editor editor = userSharePreferences.edit();
                editor.putString("username", uName);
                editor.commit();
                Intent intent = new Intent(context, FilmListActivity.class);
                context.startActivity(intent);
            }
        }
    }

If you want to have a thorough understanding of Android readers, you can find relevant information for yourself. Here I will talk about a few points, which are more critical.

_First and foremost

public static class MyAsyncTask extends AsyncTask<String, Integer, String>

_We see that there are three parameters here, namely < input, progress, output >. The second parameter we ignore first, input refers to the type of parameters we input when we execute this class. We can see that it is consistent with the type of parameters passed in by the following functions. Our Login parameter is a String.

protected  String doInBackground(String... params)

The return type of the above function is the same as the output type, and the same as the input parameter type of the following function.

protected void onPostExecute(String s)

Now the reader can basically understand this kind of thing, that is, after accessing the network in the background of doInBackground and getting the result, it is executed in onPost Execute, at least the reader can understand it so simply.

_As for the url accessed, as we mentioned in the previous article, the specific interaction with the database is done in the server. Our client only needs to understand what parameters we give the server and what the server will return to us.

As you can see, after successful login, I will jump to another Activity.

Here, I want to share with you the idea that I got the picture in the second Activity.

Firstly, I will visit this url:

        //Client
        String FilmListUrl = "http://192.168.110.1:8080/FoeServlet/FilmList";
        new MyAsyncTask(FilmListActivity.this, list, filmListAdapter).execute(FilmListUrl);

Let's see what we can do on the server side.

        //The server
        try {
            Statement statement = (Statement)connection.createStatement();
            String sql = "select * from " + DBUtil.TABLE_FILMLIST;
            ResultSet result = statement.executeQuery(sql);
            while (result.next()) {
                rs.append("name=");
                rs.append(result.getString(1));
                rs.append("introduce=");
                rs.append(result.getString(2));
                rs.append("actor=");
                rs.append(result.getString(3));
                rs.append("filmPic=");
                rs.append(result.getString(4));
                rs.append("\n");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }


        PrintWriter pw = response.getWriter();
        pw.println(rs.toString());
        pw.flush();

The server accesses the film_list table, then puts all the contents in a String and returns them to the client. Here, do we remember a picture of the first blog, which is the content of the table?

Let's look at the string that the server returns to the client.

Aha, at first glance, it seems chaotic, but it is not. Of course, how to organize the returned data depends on the reader. Anyway, the organizational method I wrote is the picture above. Daniel, don't laugh.

When the client receives this string, we only need to do so. Useful information can be extracted.

        @Override
        protected void onPostExecute(ArrayList<String> filmList) {
            for (int i = 0; i < filmList.size()-1; i++) {
                String filmData = filmList.get(i);
                String filmName = filmData.substring(filmData.indexOf("name=")+5, filmData.indexOf("introduce="));
                String filmIntroduce = filmData.substring(filmData.indexOf("introduce=")+10, filmData.indexOf("actor="));
                String filmActor = filmData.substring(filmData.indexOf("actor=")+6, filmData.indexOf("filmPic="));
                String filmPicURL = "http://192.168.110.1:8080/FoeServlet/FilmPic?PicID=" + filmData.substring(filmData.indexOf("filmPic=")+8);
                Bitmap filmPic = null;
                list.add(new Film(filmPic, filmName, filmIntroduce, filmActor));
                new MyPicLoad(list, i, filmListAdapter).execute(filmPicURL);
            }
            filmListAdapter.notifyDataSetChanged();
        }

Don't be afraid of interesting readers. Later, I will put the source code in github so that readers can see it for themselves. We see that the picture we get now is just an ID, because we don't need to store a picture in the database, we just need to store the url of the picture. That's why you press F12 on any website and see that the pictures inside are actually src=**. So, we need the ID of the picture we get, the second network visit, and the picture.

In the second access, we need byte resources from the server to read into pictures.

        @Override
        protected  byte[] doInBackground(String... params) {
            HttpURLConnection connection = null;
            byte[] picByte = null;
            try {
                URL url = new URL(params[0]);
                connection = (HttpURLConnection)url.openConnection();
                connection.setRequestMethod("GET");
                connection.setReadTimeout(8000);

                if (connection.getResponseCode() == 200) {
                    InputStream fis = connection.getInputStream();
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    byte[] bytes = new byte[1024];
                    int length = -1;
                    while ((length = fis.read(bytes)) != -1) {
                        bos.write(bytes, 0, length);
                    }
                    picByte = bos.toByteArray();
                    bos.close();
                    fis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return picByte;
        }

_Then after you get the picture, you can update ListView again.

        @Override
        protected void onPostExecute(byte[] filmPic) {
            if (filmPic != null) {
                Bitmap bitmap = BitmapFactory.decodeByteArray(filmPic, 0, filmPic.length);
                list.get(i).setFilmBitmap(bitmap);
                filmListAdapter.notifyDataSetChanged();
            }
        }

This is the end of this blog. This project will be uploaded to github

_github address: https://github.com/gjbian/Foe_Ticket

Posted by justindublin on Sat, 22 Jun 2019 14:53:53 -0700