• Android腾讯微博客户端开发四:微博发送篇(QQ表情,@搜索)


    凌晨发帖不容易啊,  有一个问题,谁做过android的自定义表情啊?貌似还没有发现有客户端有,都是图片,如果能像在电脑上那样自定义表情的功能多好,那位大哥知道,麻烦告知一声,呵呵。写完,睡觉。 
     
    我们仔细来观察下腾讯微博的qq表情发送规律,由/开始,1到3个中文或者英文字符. 

    写个工具类来测试已测试正则表达式来匹配表情。 
     

     
    在上方输入框中可以输入查询 格式为 @你选择的列表值 
     
    这个是话题输入界面,格式为#话题# 
     
    表情选择页面,这个其实是一个每行5列的GridView 

     
    此界面可看到你写的微博的内容,点击发送,发送成功 
     
    哈哈,看到了吧,我的微博首页已经显示了我刚才发送的带有话题@person和表情的微博了。 

    接下来,上代码。 

    Java代码  收藏代码
    1. public class AddWeiboActivity extends Activity implements OnClickListener{  
    2.       
    3.     private DataHelper dataHelper;  
    4.     private UserInfo user;  
    5.     private String user_default_name;  
    6.     private MyWeiboSync weibo;  
    7.     private ListView listView;  
    8.     private EditText weibo_content;  
    9.     private Button send_btn;  
    10.     private Button add_cmamera_btn;  
    11.     private Button add_at_btn;  
    12.     private Button add_topic_btn;  
    13.     private Button add_expression_btn;  
    14.     private Button add_location_btn;  
    15.     private GridView expressionGrid;  
    16.     private List<Map<String,Object>> expressionList;  
    17.     private ExpressionAdapter expressionAdapter;  
    18.     private FrameLayout operation_layout;  
    19.     private RelativeLayout add_top_bar;  
    20.       
    21.     private ListView atListView;  
    22.     private RelativeLayout atRootLayout;  
    23.     private EditText atEditText;  
    24.     private Button atEnterBtn;  
    25.     private TextView topic_tip;  
    26.       
    27.     private RelativeLayout.LayoutParams atEdiLayoutParams,atEnterBtnLayoutParams,atListViewLayoutParams,topicTipViewLayoutParams;  
    28.       
    29.     private JSONArray array;  
    30.     private Handler handler;  
    31.     private ArrayAdapter atAdapter;  
    32.     private List<String> atList;  
    33.     private AtThread thread;  
    34.     private List<String> matchStrList;//选择atList匹配的字符串  
    35.     private int flag;  
    36.     private static int FLAG_1 = 1;  
    37.     private static int FLAG_2 = 2;//1和2代表atEnterBtn的父亲控件不同  
    38.   
    39.     @Override  
    40.     protected void onCreate(Bundle savedInstanceState) {  
    41.         super.onCreate(savedInstanceState);  
    42.         setContentView(R.layout.add_weibo);  
    43.           
    44.         setUpViews();  
    45.         setUpListeners();  
    46.           
    47.         dataHelper = DataBaseContext.getInstance(getApplicationContext());  
    48.         weibo = WeiboContext.getInstance();  
    49.           
    50.         SharedPreferences preferences = getSharedPreferences("default_user",Activity.MODE_PRIVATE);  
    51.         user_default_name = preferences.getString("user_default_name""");//取得微博默认登录账号信息  
    52.           
    53.         handler = new AtHandler();  
    54.         thread = new AtThread();  
    55.         thread.start();//开启一个线程获取数据  
    56.     }  
    57.       
    58.     private void setUpViews(){  
    59.         weibo_content = (EditText)findViewById(R.id.weibo_content);  
    60.         send_btn = (Button)findViewById(R.id.send_btn);  
    61.         add_cmamera_btn = (Button)findViewById(R.id.add_cmamera_btn);  
    62.         add_at_btn = (Button)findViewById(R.id.add_at_btn);  
    63.         add_topic_btn = (Button)findViewById(R.id.add_topic_btn);  
    64.         add_expression_btn = (Button)findViewById(R.id.add_expression_btn);  
    65.         add_location_btn = (Button)findViewById(R.id.add_location_btn);  
    66.           
    67.         add_top_bar = (RelativeLayout)findViewById(R.id.add_top_bar);  
    68.         operation_layout = (FrameLayout)findViewById(R.id.operation_layout);  
    69.         expressionGrid = new GridView(this);  
    70.         expressionGrid.setNumColumns(5);  
    71.         expressionList = buildExpressionsList();  
    72.         expressionAdapter = new ExpressionAdapter(AddWeiboActivity.this, expressionList);  
    73.         expressionGrid.setAdapter(expressionAdapter);  
    74.           
    75.         //以下代码至本方法setUpViews结束,是个人纯粹蛋疼联系纯代码布局,各位老大可以改成xml布局,淡定  
    76.           
    77.         atRootLayout = new RelativeLayout(AddWeiboActivity.this);  
    78.           
    79.         atEditText = new EditText(AddWeiboActivity.this);  
    80.         atEditText.setId(10000);  
    81.           
    82.         atEnterBtn = new Button(AddWeiboActivity.this);  
    83.         atEnterBtn.setBackgroundDrawable(getResources().getDrawable(R.drawable.btn_enter_selector));  
    84.           
    85.         atListView = new ListView(AddWeiboActivity.this);  
    86.         atListView.setCacheColorHint(Color.TRANSPARENT);//防止滑屏时出现黑快,不信可以注释掉此句试一试  
    87.         atListView.setDivider(getResources().getDrawable(R.drawable.list_divider));//设置分割线  
    88.         atListView.setBackgroundColor(Color.argb(255239239239));//alpha通道一定不要设置成透明的了,要不然textView什么也看不见,因为这个我找了很久,以为代码错了,最后才发现是透明的  
    89.           
    90.         topic_tip = new TextView(AddWeiboActivity.this);  
    91.         topic_tip.setText("请输入话题");  
    92.         topic_tip.setTextSize(20);  
    93.         topic_tip.setTextColor(Color.argb(25590142189));//alpha通道一定不要设置成透明的了,要不然textView什么也看不见,因为这个我找了很久,以为代码错了,最后才发现是透明的  
    94.           
    95.         atRootLayout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));  
    96.         atEdiLayoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,80);  
    97.         atEnterBtnLayoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);  
    98.         atListViewLayoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);  
    99.         topicTipViewLayoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);  
    100.           
    101.           
    102.         //添加布局约束  
    103.         atEdiLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);  
    104.           
    105.         atEnterBtnLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP,RelativeLayout.TRUE);  
    106.         atEnterBtnLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,RelativeLayout.TRUE);  
    107.         atEnterBtnLayoutParams.setMargins(010100);//设置边距,分别代表左,上,右,下  
    108.           
    109.         atListViewLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM,RelativeLayout.TRUE);  
    110.         atListViewLayoutParams.addRule(RelativeLayout.BELOW, atEditText.getId());  
    111.           
    112.         topicTipViewLayoutParams.addRule(RelativeLayout.BELOW, atEditText.getId());  
    113.           
    114.     }  
    115.       
    116.     private void setUpListeners(){  
    117.         send_btn.setOnClickListener(this);  
    118.         add_cmamera_btn.setOnClickListener(this);  
    119.         add_at_btn.setOnClickListener(this);  
    120.         add_topic_btn.setOnClickListener(this);  
    121.         add_expression_btn.setOnClickListener(this);  
    122.         add_location_btn.setOnClickListener(this);  
    123.         expressionGrid.setOnItemClickListener(new GridItemClickListener());  
    124.         atListView.setOnItemClickListener(new AtListViewItemListener());  
    125.         atEditText.addTextChangedListener(new MyTextWatcher());  
    126.         atEnterBtn.setOnClickListener(new OnClickListener() {  
    127.             @Override  
    128.             public void onClick(View v) {  
    129.                 add_top_bar.setVisibility(View.VISIBLE);  
    130.                 weibo_content.setVisibility(View.VISIBLE);  
    131.                 operation_layout.setVisibility(View.GONE);  
    132.                 operation_layout.removeAllViews();//别忘记要移除掉  
    133.                 if(flag==FLAG_1){  
    134.                     weibo_content.setText(weibo_content.getText()+"@");  
    135.                 }else if(flag==FLAG_2){  
    136.                     weibo_content.setText(weibo_content.getText()+"#"+atEditText.getText()+"#");  
    137.                 }  
    138.                   
    139.                   
    140.             }  
    141.         });  
    142.     }  
    143.       
    144.     class AtThread extends Thread {  
    145.         @Override  
    146.         public void run() {  
    147.             String jsonStr = weibo.getFans(weibo.getAccessTokenKey(), weibo.getAccessTokenSecrect(), 200, user_default_name);  
    148.             try {  
    149.                 JSONObject dataObj = new JSONObject(jsonStr).getJSONObject("data");  
    150.                 array = dataObj.getJSONArray("info");  
    151.             } catch (JSONException e) {  
    152.                 e.printStackTrace();  
    153.             }  
    154.             //通知handler处理数据  
    155.             Message msg = handler.obtainMessage();  
    156.             handler.sendMessage(msg);  
    157.         }  
    158.     }  
    159.       
    160.     class AtHandler extends Handler {   
    161.         @Override  
    162.         public void handleMessage(Message msg){  
    163.             int size = array.length();  
    164.             atList = new ArrayList<String>();  
    165.             for(int i = 0;i<size;i++){  
    166.                 JSONObject data = array.optJSONObject(i);  
    167.                 try {  
    168.                     atList.add(data.getString("nick")+"("+data.getString("name")+")");  
    169.                 } catch (JSONException e) {  
    170.                     e.printStackTrace();  
    171.                 }  
    172.             }  
    173.             matchStrList = new ArrayList<String>();  
    174.             matchStrList.addAll(atList);  
    175.             atAdapter = new ArrayAdapter<String>(AddWeiboActivity.this,R.layout.at_list_item,R.id.at_nick_name,atList);  
    176.             atListView.setAdapter(atAdapter);  
    177.         }  
    178.     }  
    179.       
    180.     class ExpressionAdapter extends BaseAdapter {  
    181.         private Context context;  
    182.         private LayoutInflater inflater;  
    183.         private List<Map<String,Object>> list;  
    184.           
    185.         public ExpressionAdapter(Context context, List<Map<String,Object>> list) {  
    186.             super();  
    187.             this.context = context;  
    188.             this.list = list;  
    189.             this.inflater = LayoutInflater.from(context);  
    190.         }  
    191.   
    192.         @Override  
    193.         public int getCount() {  
    194.             return list.size();  
    195.         }  
    196.   
    197.         @Override  
    198.         public Object getItem(int position) {  
    199.             return list.get(position);  
    200.         }  
    201.   
    202.         @Override  
    203.         public long getItemId(int position) {  
    204.             return position;  
    205.         }  
    206.   
    207.         @Override  
    208.         public View getView(final int position, View convertView, ViewGroup parent){  
    209.             Map<String,Object> map = list.get(position);  
    210.             ImageView image = new ImageView(context);  
    211.             image.setImageDrawable((Drawable)map.get("drawable"));  
    212.             return image;  
    213.         }  
    214.     }  
    215.   
    216.     @Override  
    217.     public void onClick(View v) {  
    218.         if(operation_layout.getChildCount()>0){  
    219.             add_top_bar.setVisibility(View.VISIBLE);  
    220.             weibo_content.setVisibility(View.VISIBLE);  
    221.             operation_layout.setVisibility(View.GONE);  
    222.             operation_layout.removeAllViews();//别忘记要移除掉  
    223.             return;  
    224.         }  
    225.         switch (v.getId()) {  
    226.           
    227.         case R.id.send_btn:{  
    228.             String returnStr = weibo.publishMsg(weibo.getAccessTokenKey(), weibo.getAccessTokenSecrect(), weibo_content.getText().toString());  
    229.             try {  
    230.                 JSONObject dataObj = new JSONObject(returnStr);  
    231.                 if("ok".equals(dataObj.getString("msg"))){  
    232.                     Toast.makeText(AddWeiboActivity.this"发送成功", Toast.LENGTH_SHORT).show();//我日,记得要show,每次都搞忘记  
    233.                 }  
    234.             } catch (JSONException e) {  
    235.                 e.printStackTrace();  
    236.             }  
    237.         }  
    238.             break;  
    239.         case R.id.add_cmamera_btn:{  
    240.               
    241.         }  
    242.             break;  
    243.         case R.id.add_at_btn:{  
    244.             // 动态的组装view  
    245.             atRootLayout.removeAllViews();// 组装前先把所有的孩子拿掉  
    246.             atEditText.setText("@");  
    247.             flag = FLAG_1;//区分atEnterBtn是在哪个界面按的  
    248.             atRootLayout.addView(atEditText, atEdiLayoutParams);  
    249.             atRootLayout.addView(atEnterBtn, atEnterBtnLayoutParams);  
    250.             atRootLayout.addView(atListView, atListViewLayoutParams);  
    251.             operation_layout.addView(atRootLayout);  
    252.   
    253.             add_top_bar.setVisibility(View.GONE);// 隐藏上面的bar和文本编辑框,不让之与at选择相互影响  
    254.             weibo_content.setVisibility(View.GONE);  
    255.             operation_layout.setVisibility(View.VISIBLE);  
    256.         }  
    257.             break;  
    258.         case R.id.add_topic_btn:{  
    259.             //动态的组装view  
    260.             atRootLayout.removeAllViews();//组装前先把所有的孩子拿掉  
    261.             atEditText.setText("");  
    262.             flag = FLAG_2;//区分atEnterBtn是在哪个界面按的  
    263.             atRootLayout.addView(atEditText,atEdiLayoutParams);  
    264.             atRootLayout.addView(atEnterBtn,atEnterBtnLayoutParams);  
    265.             atRootLayout.addView(topic_tip,topicTipViewLayoutParams);  
    266.             operation_layout.addView(atRootLayout);  
    267.               
    268.             add_top_bar.setVisibility(View.GONE);// 隐藏上面的bar和文本编辑框,不让之与at选择相互影响  
    269.             weibo_content.setVisibility(View.GONE);  
    270.             operation_layout.setVisibility(View.VISIBLE);  
    271.         }  
    272.             break;  
    273.         case R.id.add_expression_btn:{  
    274.             add_top_bar.setVisibility(View.GONE);//隐藏上面的bar和文本编辑框,不让之与表情选择的gridView相互影响  
    275.             weibo_content.setVisibility(View.GONE);  
    276.             operation_layout.addView(expressionGrid);  
    277.             operation_layout.setVisibility(View.VISIBLE);  
    278.         }  
    279.             break;  
    280.         case R.id.add_location_btn:{  
    281.               
    282.         }  
    283.             break;  
    284.         default:  
    285.             break;  
    286.         }  
    287.     }  
    288.     private List<Map<String,Object>> buildExpressionsList(){  
    289.         List<Map<String,Object>> list = new ArrayList<Map<String, Object>>();  
    290.         DecimalFormat df = new DecimalFormat("000");//格式化数字  
    291.         for(int i = 0;i<105;i++){  
    292.             Map<String,Object> map = new HashMap<String, Object>();  
    293.             String formatStr = "h"+df.format(i);  
    294.             int drawableId = 0 ;  
    295.             try {  
    296.                 drawableId = R.drawable.class.getDeclaredField(formatStr).getInt(this);//反射取得id,这个地方循环套反射,是不是很耗性能啊,我没测试过,麻烦有好办法的兄弟姐妹分享一下  
    297.             } catch (IllegalArgumentException e) {  
    298.                 e.printStackTrace();  
    299.             } catch (SecurityException e) {  
    300.                 e.printStackTrace();  
    301.             } catch (IllegalAccessException e) {  
    302.                 e.printStackTrace();  
    303.             } catch (NoSuchFieldException e) {  
    304.                 e.printStackTrace();  
    305.             }  
    306.             Drawable drawable = getResources().getDrawable(drawableId);  
    307.             map.put("drawableId", formatStr);  
    308.             map.put("drawable",drawable);  
    309.             list.add(map);  
    310.         }  
    311.         return list;  
    312.     }  
    313.       
    314.     class GridItemClickListener implements OnItemClickListener {  
    315.         @Override  
    316.         public void onItemClick(AdapterView<?> adapterView, View view, int position,long arg3) {  
    317.             Map<String, Object> map = expressionList.get(position);  
    318.             String drawableId = (String)map.get("drawableId");  
    319.               
    320.             add_top_bar.setVisibility(View.VISIBLE);  
    321.             weibo_content.setVisibility(View.VISIBLE);  
    322.             operation_layout.setVisibility(View.GONE);  
    323.             operation_layout.removeAllViews();//别忘记要移除掉  
    324.               
    325.             String expressionStr=null;  
    326.             expressionStr = TextUtil.drawableIdToFaceName.get(drawableId);  
    327.             expressionStr="/"+expressionStr;  
    328.             weibo_content.setText(weibo_content.getText().toString()+expressionStr);  
    329.         }  
    330.     }  
    331.       
    332.     class MyTextWatcher implements TextWatcher{  
    333.         @Override  
    334.         public void afterTextChanged(Editable s){  
    335.             String changingStr = atEditText.getText().toString();  
    336.             if(changingStr.indexOf("@")!=-1){  
    337.                 changingStr = changingStr.substring(1);  
    338.             }  
    339.               
    340.             int size = atList.size();  
    341.             matchStrList.clear();  
    342.             for(int i = 0;i<size;i++){  
    343.                 String currentStr = atList.get(i);  
    344.                 if(currentStr.indexOf(changingStr)!=-1){  
    345.                     matchStrList.add(currentStr);  
    346.                 }  
    347.             }  
    348.             atAdapter = new ArrayAdapter<String>(AddWeiboActivity.this,R.layout.at_list_item,R.id.at_nick_name,matchStrList);  
    349.             atAdapter.notifyDataSetChanged();  
    350.             atListView.setAdapter(atAdapter);  
    351.         }  
    352.   
    353.         @Override  
    354.         public void beforeTextChanged(CharSequence s, int start, int count,  
    355.                 int after) {  
    356.               
    357.         }  
    358.   
    359.         @Override  
    360.         public void onTextChanged(CharSequence s, int start, int before,int count) {  
    361.               
    362.         }  
    363.     }  
    364.       
    365.     class AtListViewItemListener implements OnItemClickListener{  
    366.         @Override  
    367.         public void onItemClick(AdapterView<?> arg0, View arg1, int position,long arg3){  
    368.             add_top_bar.setVisibility(View.VISIBLE);  
    369.             weibo_content.setVisibility(View.VISIBLE);  
    370.             operation_layout.setVisibility(View.GONE);  
    371.             operation_layout.removeAllViews();//别忘记要移除掉  
    372.               
    373.             String str = matchStrList.get(position);  
    374.             String nickStr = str.substring(0,str.indexOf("("));  
    375.             weibo_content.setText(weibo_content.getText()+"@"+nickStr);  
    376.         }  
    377.     }  
    378. }  



    add_weibo.xml: 

    Java代码  收藏代码
    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#ffffffff" xmlns:android="http://schemas.android.com/apk/res/android">  
    3.    <RelativeLayout android:id="@+id/add_top_bar" android:background="@drawable/header" android:layout_width="fill_parent" android:layout_height="wrap_content">  
    4.         <Button android:text="发送" android:id="@+id/send_btn"  android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5.0dip" android:layout_alignParentRight="true"/>  
    5.         <TextView android:text="写广播" android:textSize="16.0sp" android:textColor="#ffffffff" android:ellipsize="middle" android:gravity="center_horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:singleLine="true" android:layout_alignParentLeft="true" android:layout_marginLeft="10.0dip" android:layout_centerVertical="true"/>  
    6.     </RelativeLayout>  
    7.    <EditText android:id="@+id/weibo_content" android:gravity="top" android:layout_below="@id/add_top_bar" android:background="@null" android:textColor="@null" android:layout_weight="1" android:layout_width="fill_parent" android:layout_height="fill_parent"/>  
    8.    <RelativeLayout android:id="@+id/add_bottom_bar" android:background="@drawable/header" android:layout_width="fill_parent" android:layout_height="50.0dip" android:layout_alignParentBottom="true" android:layout_marginTop="5.0dip">  
    9.         <Button android:id="@+id/add_cmamera_btn" android:background="@drawable/add_pic_selector" android:focusable="false" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="8.0dip" android:layout_marginRight="12.0dip" android:layout_alignParentLeft="true" android:layout_centerVertical="true" />  
    10.         <Button android:id="@+id/add_at_btn" android:background="@drawable/add_at_selector" android:focusable="false" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="12.0dip" android:layout_toRightOf="@id/add_cmamera_btn" android:layout_centerVertical="true" />  
    11.         <Button android:id="@+id/add_topic_btn" android:background="@drawable/add_topic_selector" android:focusable="false" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="12.0dip" android:layout_toRightOf="@id/add_at_btn" android:layout_centerVertical="true" />  
    12.         <Button android:id="@+id/add_expression_btn" android:background="@drawable/add_emo_selector" android:focusable="false" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="12.0dip" android:layout_toRightOf="@id/add_topic_btn" android:layout_centerVertical="true" />  
    13.         <Button android:id="@+id/add_location_btn" android:background="@drawable/add_location_selector" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/add_expression_btn" android:layout_centerVertical="true" />  
    14.         <TextView android:textSize="12.0sp" android:text="140" android:textColor="#c6cbce" android:id="@+id/remain_count" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="12.0dip" android:layout_alignParentRight="true" android:layout_centerVertical="true" />  
    15.     </RelativeLayout>  
    16.     <FrameLayout android:layout_gravity="bottom" android:id="@+id/operation_layout" android:background="@android:color/transparent" android:paddingBottom="50.0dip" android:visibility="gone" android:layout_width="fill_parent" android:layout_height="fill_parent" />  
    17. </RelativeLayout>  


    表情解析先关 :下图是drawable文件下的表情文件 
     

    Java代码  收藏代码
    1. static{//表情文件和表情id的对应的HashMap<String,String>  
    2.         drawableIdToFaceName.put("h000","调皮");  
    3.         drawableIdToFaceName.put("h001","呲牙");  
    4.         drawableIdToFaceName.put("h002","惊讶");  
    5.         drawableIdToFaceName.put("h003","难过");  
    6.         drawableIdToFaceName.put("h004","酷");  
    7.         drawableIdToFaceName.put("h005","冷汗");  
    8.         drawableIdToFaceName.put("h006","抓狂");  
  • 相关阅读:
    C#中的WebBrowser控件的使用
    xshell5 可用注册码
    一次多数据源 配置问题记录
    org.springframework.data.mongodb.core.MongoTemplate]: Constructor threw exception; nested exception is java.lang.NoSuchMethodError: org.springframework.core.convert.support.ConversionServiceFactory.cr
    关于 <mvc:argument-resolvers> 的一次使用记录
    补码、反码、原码 ~ ^ 运算
    mysql中int、bigint、smallint 和 tinyint的区别与长度的含义【转】
    tomcat优化记录
    判读40亿数字中是否有某个数字
    LinkedList源码疑问记录
  • 原文地址:https://www.cnblogs.com/afly/p/2360237.html
Copyright © 2020-2023  润新知