参考: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(); } }好了,继续学习,数据结构也要复习。