Lập trình Android – Bài 6: Thực hành xây dựng ứng dụng Calculator
Chào các bạn, trong 2 bài trước chúng ta đã tập thiết kế giao diện tương đối nhiều rồi. Để bớt sự căng thẳng và đổi gió chút thì bài này sẽ hướng dẫn các bạn làm một ứng dụng Calculator hoàn chỉnh.
[qads]
Chúng ta sẽ sử dụng code giao diện hôm trước đã thiết kế.
Ah quên, nhắc với các bạn là để làm ứng dụng này có thể tính toán nhanh chóng và không mất nhiều công sức, chúng ta sẽ dùng thư viện Balan mà mình đã xây dựng. Các bạn download file balan.jar tại đây. Tiếp theo mở chế độ Project và copy file balan.jar vào thư mục app/libs như hình
Sau đó Click chuột phải vào file balan.jar chọn Add as Library… ở gần cuối menu, hệ thống hỏi bạn có muốn add vào modul app khôgn thì cứ ok. Đợi một chút hệ thống đồng bộ là xong.
Bây giờ các bạn mở file ActivityMain.java trong thư mục app/src/main/java/{tên package} ra. Hiện tại hàm setContentViewdrrdf của chúng ta vẫn là R.layout.activity_main, các bạn thay đổi nó thành R.layout.layout_calculator để kết nối đến file giao diện của Calculator mà bạn đã thiết kế hôm trước.
package com.nguyenvanquan7826.tut5linearlayout; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.layout_calculator); } }
Rồi ok, giờ mới thực sự bắt đầu nhé.
Trước tiên, để có thể thao tác với máy tính, chúng ta cần kết nối các phần tử trong giao diện với code java thông qua các biến tương ứng.
package com.nguyenvanquan7826.tut5linearlayout; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.TextView; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private TextView tvMath; private TextView tvResult; private int[] idButton = { R.id.btn0, R.id.btn1, R.id.btn2, R.id.btn3, R.id.btn4, R.id.btn5, R.id.btn6, R.id.btn7, R.id.btn8, R.id.btn9, R.id.btnDot, R.id.btnResult, R.id.btnPlus, R.id.btnSub, R.id.btnMul, R.id.btnDiv, R.id.btnC, R.id.btnOpen, R.id.btnClose }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.layout_calculator); connectView(); } private void connectView() { tvMath = (TextView) findViewById(R.id.tvMath); tvResult = (TextView) findViewById(R.id.tvResult); for (int i = 0; i < idButton.length; i++) { findViewById(idButton[i]).setOnClickListener(this); } } @Override public void onClick(View view) { } }
Các bạn chú ý trong code trên việc kết nối TextView Math và Result là bình thường, riêng kết nối các Button là không bình thường. Lý do là mình nhận thấy có rất nhiều button cần kết nối và chúng đều cần bắt sự kiện cả. Do vậy ý nghĩ hiện lên là liệu có thể cho vào vòng lặp để lặp đi lặp lại công việc giống nhau đó? Vì vậy mình đã cho các id của chúng vào một mảng idButton. Id của mỗi View thực chất được chuyển thành kiểu nguyên trong hệ thống, vì vậy mảng này có kiểu là int. Ngoài ra việc kết nối và bắt sự kiện cho mỗi button trong vòng for cũng có sự khác biệt. Chúng ta không ép kiểu về button mà vừa kết nối vừa bắt sự kiện ngay qua chuỗi lệnh findViewById(idButton[i]).setOnClickListener(this);
Lý do là hàm findViewById sẽ trả về cho chúng ta một View (và từ đó thông thường chúng ta ép về kiểu đúng của nó như Button, TextView,…) mà mỗi View đều có thể bắt sự kiện Click (kể cả TextView, EditText,…) nên chúng ta gọi ngay được setOnClickListener sau đó mà không cần ép kiểu về Button.
Bây giờ công việc tiếp theo là xử lý sự kiện click button. Tại đây chúng ta phân ra làm 3 loại button: Button số, Button phép toán và Button Xử lý phép toán.
Button số và button phép toán thì khi click vào button nào, chúng ta cứ thêm text tương ứng vào biểu thức. Còn button xử lý (button C và button = ) thì thực hiện công việc tính toán hoặc xóa màn hình. Khi click Button bằng, chúng ta gọi hàm valueMath của đối tượng Balan trong thư viện Balan mà chúng ta đã thêm vào ban đầu, nó sẽ tính cho chúng ta kết quả.
package com.nguyenvanquan7826.tut5linearlayout; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.TextView; import cachhoc.net.Balan; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private TextView tvMath; private TextView tvResult; private int[] idButton = { R.id.btn0, R.id.btn1, R.id.btn2, R.id.btn3, R.id.btn4, R.id.btn5, R.id.btn6, R.id.btn7, R.id.btn8, R.id.btn9, R.id.btnDot, R.id.btnPlus, R.id.btnSub, R.id.btnMul, R.id.btnDiv, R.id.btnOpen, R.id.btnClose, R.id.btnC, R.id.btnResult }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.layout_calculator); connectView(); } private void connectView() { tvMath = (TextView) findViewById(R.id.tvMath); tvResult = (TextView) findViewById(R.id.tvResult); for (int i = 0; i < idButton.length; i++) { findViewById(idButton[i]).setOnClickListener(this); } init(); } private void init() { tvMath.setText("|"); tvResult.setText("0"); } @Override public void onClick(View view) { int id = view.getId(); // check button number and button operator for (int i = 0; i < idButton.length - 2; i++) { if (id == idButton[i]) { String text = ((Button) findViewById(id)).getText().toString(); // clear char | on top if (tvMath.getText().toString().trim().equals("|")) { tvMath.setText(""); } tvMath.append(text); return; } } // clear screen if (id == R.id.btnC) { init(); return; } // calculation if (id == R.id.btnResult) { cal(); } } private void cal() { String math = tvMath.getText().toString().trim(); if (math.length() > 0) { Balan balan = new Balan(); String result = balan.valueMath(math) + ""; String error = balan.getError(); // check error if (error != null) { tvResult.setText(error); } else { // show result tvResult.setText(result); } } } }
Vậy là xong, kết quả của chúng ta đây nhé.
anh ơi nếu có thêm phím về sin cos tan thì xử lý tn ạ
Thư viện có thể tính đk sin(x), cos(x), tan(x). Bạn cứ viết bình thường thôi.
anh Quan khi mình ấn dấu ) rồi ấn = thi` app bị die , không biet xu ly the nào ạ
:V
có cần thuật toán riêng cho phần sin cos tan k a!sao của a k có
Trong thư viện của a đã tính được những cái đó rồi.
anh oi khi em tao cai layout(land) chỉ thiết kế lại lại cái giao dien ngang cho bài của anh thì app bị kill và báo lỗi thế này , em xin hỏi cách fix ạ
08-01 01:13:12.811 15250-15250/com.example.dell.calculator E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.dell.calculator, PID: 15250
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.dell.calculator/com.example.dell.calculator.MainActivity}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2338)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2390)
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3930)
at android.app.ActivityThread.access$900(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1327)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:5292)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:824)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:640)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at com.example.dell.calculator.MainActivity.connectView(MainActivity.java:42)
at com.example.dell.calculator.MainActivity.onCreate(MainActivity.java:34)
at android.app.Activity.performCreate(Activity.java:5264)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1088)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2302)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2390)
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3930)
at android.app.ActivityThread.access$900(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1327)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:5292)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:824)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:640)
at dalvik.system.NativeStart.main(Native Method)
Bạn tìm cách bắt sự kiện thay chuyển hướng màn hình để fix nhé.
Cảm ơn tut của anh ạ
Anh cho em hỏi thêm mới, em muốn bắt không cho người ta nhập sai như máy tính thật ấy ạ, kiểu như không được nhập hơn hai dấu . trong 1 số, không được đóng ngoặc trước khi mở ngoặc, không được chia cho số 0… thì làm nào ạ
Thế cái này em phải dùng bắt sự kiện cho EditText là onTextChange nhé.
thư viện libs là mình tự tạo hay có sẵn ad
Share mình code đc ko bạn ơi.
Email: nguyenngocluh14@gmail.com
Code ở trong bài luôn bạn nhé. Code giao diện ở bài 5, nhìn bên phải trên đầu là thấy bài 5.
A ơi e bị lỗi phần tính căn bậc 2 và tính %.
– Nếu nhập √4 chẳng hạn thì sẽ báo “String input math”
– Còn nếu ấn 50% thì ký tự % không được append vào TextView và ấn bằng thì chỉ hiện đúng cái số kia thôi.
Vậy là lỗi của e là như thế nào ạ, mong a giải thích.
E cảm ơn!
căn 4 mình có bị đâu nhỉ.
a ơi cho em hỏi file balan.jar là file balan.java hả ?
.jar là file đã build, .java là file mã nguồn.
anh ơi cho em hỏi lỗi này là sao và sửa thế nào ạ
“C:\Program Files\Android\Android Studio\jre\bin\java.exe” -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:54743,suspend=y,server=n -javaagent:C:\Users\Admin\.AndroidStudio4.0\system\groovyHotSwap\gragent.jar -javaagent:C:\Users\Admin\.AndroidStudio4.0\system\captureAgent\debugger-agent.jar -Dfile.encoding=windows-1252 -classpath “C:\Program Files\Android\Android Studio\lib\idea_rt.jar” -jar C:\Users\Admin\AndroidStudioProjects\android_co_ban\app\libs\balan.jar
Connected to the target VM, address: ‘127.0.0.1:54743’, transport: ‘socket’
no main manifest attribute, in C:\Users\Admin\AndroidStudioProjects\android_co_ban\app\libs\balan.jar
Disconnected from the target VM, address: ‘127.0.0.1:54743’, transport: ‘socket’
Process finished with exit code 1
Bạn debug mới ra được chứ cái kia mình thấy báo liên quan tới socket