又学了一天,感觉一天都不知道在干嘛,都在写这个菜鸟计算器。
参考:https://blog.csdn.net/sakurakider/article/details/76283801
昨天随便弄了个计算器界面之后就睡觉了,实现我完全不会,今天早上早早起来就为了搞定它,是越搞越头疼,优先级问题我居然想不到栈,我学到狗身上了,都还给老师了,service使用我居然也能忘,真的蠢,忘了吃饭,忘了睡觉也不能忘了service啊。作业后面3个要求都没做出来,还得努力。
xml如下,这是漏洞百出的界面,别喷我,饶了我这脆弱的心灵:
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:padding="10dp"
android:background="#bbbbbb">
<TextView
android:id="@+id/tv_result"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:background="#fff"
android:padding="8dp"
android:gravity="center_vertical|right"
android:text="0"
android:textSize="25sp"
android:textColor="#aaaaaa"
/>
<TableRow android:layout_marginTop="25dp">
<Button
android:id="@+id/btn_7"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="70dp"
android:text="7"
android:textSize="25sp"
/>
<Button
android:id="@+id/btn_8"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="70dp"
android:text="8"
android:textSize="25sp"
/>
<Button
android:id="@+id/btn_9"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="70dp"
android:text="9"
android:textSize="25sp"
/>
<Button
android:id="@+id/btn_plus"
android:layout_width="100dp"
android:layout_height="70dp"
android:text="+"
android:textSize="25sp"
/>
</TableRow>
<TableRow android:layout_marginTop="10dp">
<Button
android:id="@+id/btn_4"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="70dp"
android:text="4"
android:textSize="25sp"
/>
<Button
android:id="@+id/btn_5"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="70dp"
android:text="5"
android:textSize="25sp"
/>
<Button
android:id="@+id/btn_6"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="70dp"
android:text="6"
android:textSize="25sp"
/>
<Button
android:id="@+id/btn_sub"
android:layout_width="100dp"
android:layout_height="70dp"
android:text="-"
android:textSize="25sp"
/>
</TableRow>
<TableRow android:layout_marginTop="10dp">
<Button
android:id="@+id/btn_1"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="70dp"
android:text="1"
android:textSize="25sp"
/>
<Button
android:id="@+id/btn_2"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="70dp"
android:text="2"
android:textSize="25sp"
/>
<Button
android:id="@+id/btn_3"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="70dp"
android:text="3"
android:textSize="25sp"
/>
<Button
android:id="@+id/btn_multiply"
android:layout_width="100dp"
android:layout_height="70dp"
android:text="*"
android:textSize="25sp"
android:gravity="center"
/>
</TableRow>
<TableRow android:layout_marginTop="10dp">
<Button
android:id="@+id/btn_0"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="70dp"
android:text="0"
android:textSize="25sp"
/>
<Button
android:id="@+id/btn_point"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="70dp"
android:text="."
android:textSize="25sp"
/>
<Button
android:id="@+id/btn_equal"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="70dp"
android:text="="
android:textSize="25sp"
/>
<Button
android:id="@+id/btn_division"
android:layout_width="100dp"
android:layout_height="70dp"
android:text="/"
android:textSize="25sp"
/>
</TableRow>
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="8dp">
<TextView
android:padding="8dp"
android:id="@+id/tv_showLog"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:text="Log"
android:textSize="18sp"
android:textColor="#fff"
android:background="#000000"
/>
</LinearLayout>
</TableLayout>
效果图:
作业要求用service,所以首先创建Service类,service使用线程池新建了一个线程用来转换中缀表达式和计算,应该用IntentService更好吧。但是视频讲的是IntentService所以就想试试Service,计算完成后将结果放入Intent,在通过发送广播的方式传回结果。service代码如下:
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import java.util.concurrent.Executors;
public class ComputeService extends Service {
public static final String ACTION_COMPUTE = "ACTION_COMPUTE"; //action标识
InfixInToSuffix infixInToSuffix = new InfixInToSuffix(); //转化和计算的类,别人写的
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(final Intent intent, int flags, int startId) {
Executors.defaultThreadFactory().newThread(new Runnable() {
@Override
public void run() {
StringBuilder a = new StringBuilder(intent.getStringExtra("text"));//获取中缀表达式
String text = infixInToSuffix.toSuffix(a);//中缀表达式转换为后缀表达式
Intent result = new Intent();
result.setAction(ACTION_COMPUTE);
result.putExtra("text","Get Task!" + a);
result.putExtra("result",infixInToSuffix.dealEquation(text));//获取后缀表达式计算结果
sendBroadcast(result);//发送广播
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
service里面的InfixInToSuffix就是别人写好的中缀表达式转换为后缀表达式还有后缀表达式计算,中缀转后缀规则:
1.遇到操作数,直接输出;
2.栈为空时,遇到运算符,入栈;
3.遇到左括号,将其入栈;
4.遇到右括号,执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出;
5.遇到其他运算符’+”-”*”/’时,弹出所有优先级大于或等于该运算符的栈顶元素,然后将该运算符入栈;
6.最终将栈中的元素依次出栈,输出。
原文:https://blog.csdn.net/qq_34992845/article/details/70313588
InfixInToSuffix代码如下:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class InfixInToSuffix {
//使用集合定义好符号的运算优先级别
private static final Map<Character,Integer> basic =new HashMap<Character, Integer>();
static {
basic.put('-',1);
basic.put('+', 1);
basic.put('*', 2);
basic.put('/', 2);
basic.put('(', 0);//在运算中()的优先级最高,但是此处因程序中需要 故设置为0
}
//将中缀表达式转换为后缀表达式
public String toSuffix(StringBuilder infix){
List<String> queue = new ArrayList<String>();//定义队列,用于存储数字以及最后的后缀表达式
List<Character> stack = new ArrayList<Character>(); //定义栈,用于存储运算符,最后stack中会被弹空
char[] charArr = infix.substring(0,infix.length()).trim().toCharArray(); //字符数组,用于拆分数字或符号
String standard = "*/+-()"; //判定标准 将表达式中会出现的运算符写出来
char ch = '&'; //在循环中用来保存 字符数组的当前循环变量的 这里仅仅是初始化一个值 没有意义
int len = 0; //用于记录字符长度 【例如100*2,则记录的len为3 到时候截取字符串的前三位就是数字】
for (int i = 0; i < charArr.length; i++) {//开始迭代
ch = charArr[i];//保存当前迭代变量
if(Character.isDigit(ch)) { //如果当前变量为 数字
len++;
}else if(ch == '.'){ //如果当前变量为 . 会出现在小数里面
len++;
}else if(standard.indexOf(ch) != -1) {//如果是上面标准中的 任意一个符号
if(len > 0) { //长度也有
queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len, i)));//说明符号之前的可以截取下来做数字
len = 0; //长度置空
}
if(ch == '(') { //如果是左括号
stack.add(ch);//将左括号 放入栈中
continue; //跳出本次循环 继续找下一个位置
}
if (!stack.isEmpty()) { //如果栈不为empty
int size = stack.size() - 1;//获取栈的大小-1 即代表栈最后一个元素的下标
boolean flag = false; //设置标志位
while (size >= 0 && ch == ')' && stack.get(size) != '(') { //若当前ch为右括号,则 栈里元素从栈顶一直弹出,直到弹出到 左括号
queue.add(String.valueOf(stack.remove(size)));//注意此处条件:ch并未入栈,所以并未插入队列中;同样直到找到左括号的时候,循环结束了,所以左括号也不会放入队列中【也就是:后缀表达式中不会出现括号】
size--;//size-- 保证下标永远在栈最后一个元素【栈中概念:指针永远指在栈顶元素】
flag = true; //设置标志位为true 表明一直在取()中的元素
}
if(ch==')'&&stack.get(size) == '('){
flag = true;
}
while (size >= 0 && !flag && basic.get(stack.get(size)) >= basic.get(ch)) { //若取得不是()内的元素,并且当前栈顶元素的优先级>=对比元素 那就出栈插入队列
queue.add(String.valueOf(stack.remove(size)));//同样 此处也是remove()方法,既能得到要获取的元素,也能将栈中元素移除掉
size--;
}
}
if(ch != ')') { //若当前元素不是右括号
stack.add(ch); //就要保证这个符号 入栈
} else { //否则就要出栈 栈内符号
stack.remove(stack.size() - 1);
}
}
if(i == charArr.length - 1) { //如果已经走到了 中缀表达式的最后一位
if(len > 0) { //如果len>0 就截取数字
queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len+1, i+1)));
}
int size = stack.size() - 1; //size表示栈内最后一个元素下标
while (size >= 0) { //一直将栈内 符号全部出栈 并且加入队列中 【最终的后缀表达式是存放在队列中的,而栈内最后会被弹空】
queue.add(String.valueOf(stack.remove(size)));
size--;
}
}
}
String a = queue.toString();
return a.substring(1,a.length()-1);
}
public String dealEquation(String equation){
String [] arr = equation.split(", "); //根据, 拆分字符串
List<String> list = new ArrayList<String>(); //用于计算时存储运算过程的集合【例如list中当前放置 100 20 5 / 则取出20/5 最终将结果4存入list 此时list中结果为 100 4 】
for (int i = 0; i < arr.length; i++) { //此处就是上面说的运算过程,因为list.remove的缘故,所以取出最后一个数个最后两个数 都是size-2
int size = list.size();
switch (arr[i]) {
case "+":
double a = Double.parseDouble(list.remove(size-2))
+ Double.parseDouble(list.remove(size-2));
list.add(String.valueOf(a));
break;
case "-":
double b = Double.parseDouble(list.remove(size-2))
- Double.parseDouble(list.remove(size-2));
list.add(String.valueOf(b));
break;
case "*":
double c = Double.parseDouble(list.remove(size-2))
* Double.parseDouble(list.remove(size-2));
list.add(String.valueOf(c));
break;
case "/":
double d = Double.parseDouble(list.remove(size-2))
/ Double.parseDouble(list.remove(size-2));
list.add(String.valueOf(d));
break;
default:
list.add(arr[i]);
break; //如果是数字 直接放进list中
}
}
return list.size() == 1 ? list.get(0) : "运算失败" ; //最终list中仅有一个结果,否则就是算错了
}
最后,数据处理完了,在MainActivity里注册并接受广播,判断是否是你要的广播,再获取Service发送过来的Intent里的内容输出到TextView中就好了。代码如下:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView tv_show;
private TextView tv_log;
private Button btn_0,btn_1,btn_2,btn_3,btn_4,btn_5,btn_6,btn_7, btn_8,btn_9,
btn_plus,btn_sub,btn_multiply,btn_divide,btn_point,btn_equal;
private StringBuilder builder = new StringBuilder();
private String[] log = new String[10];
private MyBroadcastReceiver myBroadcastReceiver;
private String result;
private String text;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews(); //初始化视图
registerBroadcastReceiver(); //注册广播接收者
}
/**
* 注册广播接收器
*/
private void registerBroadcastReceiver() {
myBroadcastReceiver = new MyBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter(ComputeService.ACTION_COMPUTE);
registerReceiver(myBroadcastReceiver,intentFilter);
}
/**
* 初始化视图
*/
private void initViews() {
tv_log = findViewById(R.id.tv_showLog);
tv_show = findViewById(R.id.tv_result);
btn_0 = findViewById(R.id.btn_0);
btn_1 = findViewById(R.id.btn_1);
btn_2 = findViewById(R.id.btn_2);
btn_3 = findViewById(R.id.btn_3);
btn_4 = findViewById(R.id.btn_4);
btn_5 = findViewById(R.id.btn_5);
btn_6 = findViewById(R.id.btn_6);
btn_7 = findViewById(R.id.btn_7);
btn_8 = findViewById(R.id.btn_8);
btn_9 = findViewById(R.id.btn_9);
btn_plus = findViewById(R.id.btn_plus);
btn_sub = findViewById(R.id.btn_sub);
btn_multiply = findViewById(R.id.btn_multiply);
btn_divide = findViewById(R.id.btn_division);
btn_point = findViewById(R.id.btn_point);
btn_equal = findViewById(R.id.btn_equal);
btn_point.setOnClickListener(this);
btn_plus.setOnClickListener(this);
btn_sub.setOnClickListener(this);
btn_multiply.setOnClickListener(this);
btn_divide.setOnClickListener(this);
btn_equal.setOnClickListener(this);
btn_0.setOnClickListener(this);
btn_1.setOnClickListener(this);
btn_2.setOnClickListener(this);
btn_3.setOnClickListener(this);
btn_4.setOnClickListener(this);
btn_5.setOnClickListener(this);
btn_6.setOnClickListener(this);
btn_7.setOnClickListener(this);
btn_8.setOnClickListener(this);
btn_9.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_0:
builder = builder.append("0");
tv_show.setText(builder);
break;
case R.id.btn_1:
builder = builder.append("1");
tv_show.setText(builder);
break;
case R.id.btn_2:
builder = builder.append("2");
tv_show.setText(builder);
break;
case R.id.btn_3:
builder = builder.append("3");
tv_show.setText(builder);
break;
case R.id.btn_4:
builder = builder.append("4");
tv_show.setText(builder);
break;
case R.id.btn_5:
builder = builder.append("5");
tv_show.setText(builder);
break;
case R.id.btn_6:
builder = builder.append("6");
tv_show.setText(builder);
break;
case R.id.btn_7:
builder = builder.append("7");
tv_show.setText(builder);
break;
case R.id.btn_8:
builder = builder.append("8");
tv_show.setText(builder);
break;
case R.id.btn_9:
builder = builder.append("9");
tv_show.setText(builder);
break;
case R.id.btn_plus:
builder = builder.append("+");
tv_show.setText(builder);
break;
case R.id.btn_sub:
builder = builder.append("-");
tv_show.setText(builder);
break;
case R.id.btn_multiply:
builder = builder.append("*");
tv_show.setText(builder);
break;
case R.id.btn_division:
builder = builder.append("/");
tv_show.setText(builder);
break;
case R.id.btn_point:
builder = builder.append(".");
tv_show.setText(builder);
break;
case R.id.btn_equal:
Intent intent = new Intent(MainActivity.this,ComputeService.class);
intent.putExtra("text",builder.toString());//将文本信息存入intent
startService(intent);//开启服务
builder = builder.delete(0,builder.length());//清除文本
tv_show.setText(builder);
break;
}
}
/**
* 重写广播接收器的Receive抽象方法,用以接收数据
*/
class MyBroadcastReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {//接收广播传来的intent
if (ComputeService.ACTION_COMPUTE == intent.getAction()) {
result = intent.getStringExtra("result");
text = intent.getStringExtra("text");
tv_log.setText(text + "\nTask is finished and result is " + result);
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
好了,继续学习,数据结构也要复习。