Android5.0開發範例大全 讀書筆記(六)

来源:http://www.cnblogs.com/xx-wqj/archive/2016/10/23/5988089.html
-Advertisement-
Play Games

(六)與系統交互 6.1後臺通知 1.關於後臺通知,下麵展示6種樣式。值得一提的是,筆者的小米5只能顯示基本樣式,雷軍真是良心廠商啊。 2.首先上佈局xml 3.接著是完整代碼 6.3定時執行周期任務 1.AlarmManager用來管理和執行任務,可以在程式沒有運行的時候執行。並且有多種啟動和計算 ...


(六)與系統交互

6.1後臺通知

1.關於後臺通知,下麵展示6種樣式。值得一提的是,筆者的小米5只能顯示基本樣式,雷軍真是良心廠商啊。

2.首先上佈局xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
>

    <RadioGroup
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:id="@+id/options_group">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Rich Styles"/>
        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/option_basic"
            android:text="Basic Notification"
            android:checked="true"/>
        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/option_bigtext"
            android:text="BigText Style"
            />
        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/option_bigpicture"
            android:text="BigPicture Style"
            />
        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/option_inbox"
            android:text="Inbox Style"
            />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:text="Secured Styles"/>
        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/option_private"
            android:text="Public Version LockScreen" />
        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/option_secret"
            android:text="Secret LockScreen" />
        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/option_headsup"
            android:text="Heads-Up Notification" />
    </RadioGroup>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Post a Notification"
        android:onClick="onPostClick"/>
</LinearLayout>

3.接著是完整代碼

ublic class NotificationActivity extends AppCompatActivity {
    private RadioGroup mOptionsGroup;
    private static Handler mHandle = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_notification);
        mOptionsGroup = (RadioGroup) findViewById(R.id.options_group);

    }

    public void onPostClick(View view) {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        final int noteId = mOptionsGroup.getCheckedRadioButtonId();
        Notification note = null;
        switch (noteId) {
            case R.id.option_basic:
            case R.id.option_bigtext:
            case R.id.option_bigpicture:
            case R.id.option_inbox:
                note = buildStyledNotification(noteId);
                break;
            case R.id.option_private:
            case R.id.option_secret:
            case R.id.option_headsup:

                note = buildSecuredNotification(noteId);
                break;
        }
        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        manager.notify(noteId, note);
    }

    private Notification buildStyledNotification(int type) {
        Intent launchIntent = new Intent(this, NotificationActivity.class);
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, launchIntent, 0);

        NotificationCompat.Builder builder = new NotificationCompat.Builder(NotificationActivity.this);
        builder.setSmallIcon(R.mipmap.ic_launcher)
                .setTicker("something happen")
                .setWhen(System.currentTimeMillis())
                .setAutoCancel(true)
                .setDefaults(Notification.DEFAULT_SOUND)
                .setContentTitle("we are finished")
                .setContentText("click here")
                .setContentIntent(contentIntent);

        switch (type) {
            case R.id.option_basic:
                return builder.build();
            case R.id.option_bigtext:
                builder.addAction(android.R.drawable.ic_menu_call, "Call", contentIntent);
                builder.addAction(android.R.drawable.ic_menu_recent_history, "History", contentIntent);

                NotificationCompat.BigTextStyle textStyle = new NotificationCompat.BigTextStyle(builder);
                textStyle.bigText("BigText Mode");
                return textStyle.build();
            case R.id.option_bigpicture:
                builder.addAction(android.R.drawable.ic_menu_compass, "View Location", contentIntent);

                NotificationCompat.BigPictureStyle pictureStyle = new NotificationCompat.BigPictureStyle(builder);
                pictureStyle.bigPicture(BitmapFactory.decodeResource(getResources(), R.mipmap.cat));
                return pictureStyle.build();
            case R.id.option_inbox:
                NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle(builder);
                inboxStyle.setSummaryText("4 new tasks")
                        .addLine("make dinner")
                        .addLine("call mom")
                        .addLine("call handsome")
                        .addLine("call father");
                return inboxStyle.build();
            default:
                throw new IllegalArgumentException("Unknown Type");
        }
    }

    private Notification buildSecuredNotification(int type) {
        Intent launchIntent = new Intent(this, NotificationActivity.class);
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, launchIntent, 0);

        NotificationCompat.Builder builder = new NotificationCompat.Builder(NotificationActivity.this);
        builder.setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("account balance update")
                .setContentText("your account balance is -250")
                .setStyle(new NotificationCompat.BigTextStyle().bigText("Your account balance is-250 please pay"))
                .setContentIntent(contentIntent);


        switch (type) {
            case R.id.option_private:
                Notification publicNote = new Notification.Builder(this)
                        .setSmallIcon(R.mipmap.ic_launcher)
                        .setContentTitle("Account Notification")
                        .setContentText("an important message")
                        .setContentIntent(contentIntent)
                        .build();
                return builder.setPublicVersion(publicNote).build();

            case R.id.option_secret:
                return builder.setVisibility(Notification.VISIBILITY_SECRET).build();
            case R.id.option_headsup:
                return builder.setDefaults(Notification.DEFAULT_SOUND)
                        .setPriority(Notification.PRIORITY_HIGH)
                        .build();
            default:
                throw new IllegalArgumentException("Unknown Type");
        }
    }
}

 6.3定時執行周期任務

1.AlarmManager用來管理和執行任務,可以在程式沒有運行的時候執行。並且有多種啟動和計算時間的方式

  定義一個廣播接收者,在其中附加需要執行的操作

public class AlarmReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Calendar now=Calendar.getInstance();
        DateFormat format= SimpleDateFormat.getTimeInstance();
        Toast.makeText(context,format.format(now.getTime()),Toast.LENGTH_SHORT).show();
    }

}

  通過AlarmManager設置時間任務

public void start(View view) {
        Toast.makeText(this,"Scheduled",Toast.LENGTH_SHORT).show();
        manager.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime()+ interval, interval,mAlarmIntent);

    }

  為了方便,下麵寫出全部代碼

  其中start是間隔一段時間執行任務

  clock是在指定時間執行任務

public class AlarmActivity extends AppCompatActivity {
private PendingIntent mAlarmIntent;
    private AlarmManager manager;
    private long interval;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_timing);
        Intent launchIntent=new Intent(this,AlarmReceiver.class);
        mAlarmIntent=PendingIntent.getBroadcast(this,0,launchIntent,0);
        manager = (AlarmManager) getSystemService(ALARM_SERVICE);
        interval = 5*1000;
    }

    public void start(View view) {
        Toast.makeText(this,"Scheduled",Toast.LENGTH_SHORT).show();
        manager.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime()+ interval, interval,mAlarmIntent);

    }

    public void stop(View view) {
        Toast.makeText(this,"Canceled",Toast.LENGTH_SHORT).show();
        manager.cancel(mAlarmIntent);
    }

    public void clock(View view) {
        long oneDay=24*3600*1000;
        long firstTime;
        Calendar startTime=Calendar.getInstance();
        startTime.set(Calendar.HOUR_OF_DAY,17);
        startTime.set(Calendar.MINUTE,18);
        startTime.set(Calendar.SECOND,0);
        Calendar now=Calendar.getInstance();
        if(now.before(startTime)){
            firstTime=startTime.getTimeInMillis();
            System.out.println(firstTime);
        }else {
            startTime.add(Calendar.DATE,1);
            firstTime=startTime.getTimeInMillis();
        }
        manager.setRepeating(AlarmManager.RTC_WAKEUP,firstTime,oneDay,mAlarmIntent);

    }
}

2.JobScheduler也可以實現類似的功能

   1.首先自定義一個service繼承自JobService

public class WorkService extends JobService

  在內部放一個handler來進行簡單的隊列處理

   private Handler mJobProcessor=new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            JobParameters parameters= (JobParameters) msg.obj;
            System.out.println(parameters.getJobId());
            doWork();
            jobFinished(parameters,false);
        return true;
        }
    });

  實現onStartJob()方法,

 @Override
    public boolean onStartJob(JobParameters params) {
        mJobProcessor.sendMessageDelayed(Message.obtain(mJobProcessor,MSG_JOB,params),7500);
        return true;
    }

  實現onStopJob()方法

 @Override
    public boolean onStopJob(JobParameters params) {
        mJobProcessor.removeMessages(MSG_JOB);
        return false;
    }

  實現具體處理任務的doWork()方法

 private void doWork() {
        Calendar now=Calendar.getInstance();
        DateFormat formatter= SimpleDateFormat.getTimeInstance();
        Toast.makeText(this,formatter.format(now.getTime()),Toast.LENGTH_SHORT).show();
    }

  2.在主函數中調用JobScheduler

public class JobSchedulerActivity extends AppCompatActivity {
    private static final int JOB_ID = 1;
    private JobScheduler scheduler;
    private JobInfo info;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_job_scheduler);
        scheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
        long interval =  5 * 1000;
        info = new JobInfo.Builder(JOB_ID, new ComponentName(getPackageName(), WorkService.class.getName()))
                .setPeriodic(interval)
                .build();
    }

    public void start(View view) {

        int result = scheduler.schedule(info);
        if (result <= 0) {
            Toast.makeText(this, "Error", Toast.LENGTH_SHORT).show();
        }
    }

    public void stop(View view) {
        scheduler.cancel(JOB_ID);
    }
}

6.4創建粘性操作

1.粘性操作是指當應用程式被用戶終止時也可以執行的一個或多個操作.

2.IntentService會將要執行的任務放到隊列中,然後逐個請求,全部處理完後終結自己

   以下是自定義IntentService的完整代碼

public class OperationsManager extends IntentService {
    public static final String ACTION_EVENT = "ACTION_EVENT";
    public static final String ACTION_WARNING = "ACTION_WARNING";
    public static final String ACTION_ERROR = "ACTION_ERROR";
    public static final String EXTRA_NAME = "eventName";

    private static final String LOGTAG = "com.joshua.log";
    private IntentFilter matcher;

    public OperationsManager() {
        super("OperationsManager");
        matcher = new IntentFilter();
        matcher.addAction(ACTION_EVENT);
        matcher.addAction(ACTION_WARNING);
        matcher.addAction(ACTION_ERROR);
    }


    @Override
    protected void onHandleIntent(Intent intent) {
        if (!matcher.matchAction(intent.getAction())) {
            Toast.makeText(this, "Invalid Request", Toast.LENGTH_SHORT).show();
        }
        switch (intent.getAction()) {
            case ACTION_EVENT:
                logEvent(intent.getStringExtra(EXTRA_NAME));
                break;
            case ACTION_WARNING:
                logWarning(intent.getStringExtra(EXTRA_NAME));
                break;
            case ACTION_ERROR:
                logError(intent.getStringExtra(EXTRA_NAME));
                break;
        }

    }

    private void logError(String name) {
        try {
            Thread.sleep(5000);
            Log.i(LOGTAG,name);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    private void logWarning(String name) {
        try {
            Thread.sleep(5000);
            Log.w(LOGTAG,name);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void logEvent(String name) {
        try {
            Thread.sleep(5000);
            Log.e(LOGTAG,name);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

2.在activity中通過Intent調用IntentService

public class ReportActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_report);
        logEvent("CREATE");
    }

    @Override
    protected void onStart() {
        super.onStart();
        logEvent("START");
    }

    @Override
    protected void onResume() {
        super.onResume();
        logEvent("RESUME");
    }

    @Override
    protected void onPause() {
        super.onPause();
        logEvent("PAUSE");
    }

    @Override
    protected void onStop() {
        super.onStop();
        logEvent("STOP");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        logEvent("DESTROY");
    }

    private void logEvent(String event){
        Intent intent=new Intent(this,OperationsManager.class);
        intent.setAction(OperationsManager.ACTION_EVENT);
        intent.putExtra(OperationsManager.EXTRA_NAME,event);
        startService(intent);
    }

    private void logWarning(String event){
        Intent intent=new Intent(this,OperationsManager.class);
        intent.setAction(OperationsManager.ACTION_WARNING);
        intent.putExtra(OperationsManager.EXTRA_NAME,event);
        startService(intent);
    }
}

6.6分享內容

1.通過Intent啟動系統的其他相關程式

 public void share(View view) {
        Intent intent=new Intent(Intent.ACTION_SEND);
        intent.setType("text/plain");
        intent.putExtra(Intent.EXTRA_TEXT,"分享");
        startActivity(Intent.createChooser(intent,"Share..."));
    }

6.10讀取設備媒體和文檔

1.通過Intent獲取感興趣的設備內容,比如image/video/audio

  不過筆者的小米5不管你調用的是什麼,它都給你彈出文件管理器的首頁……

intent = new Intent();
        if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.KITKAT){
            intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
        }else {
            intent.setAction(Intent.ACTION_GET_CONTENT);
        }
        intent.addCategory(Intent.CATEGORY_OPENABLE);

    }
    public void image(View view) {
       intent.setType("image/*");
        startActivityForResult(intent,REQUEST_IMAGE);
    }

    public void video(View view) {
        intent.setType("video/*");
        startActivityForResult(intent,REQUEST_VIDEO);
    }

    public void audio(View view) {
        intent.setType("audio/*");
        startActivityForResult(intent,REQUEST_AUDIO);
    }

6.16自定義任務棧

1.當程式A的A3界面被程式B的B3界面啟動後,按返回是返回B3還是A2呢?當然是B3啦,因為屬於程式A的任務棧並沒有被創建。

  因此如果想要返回A2,則必須啟動A的任務棧。

2.首先,創建一個根界面

public class RootActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_root);
    }

    public void next(View view) {
        Intent intent=new Intent(this,ItemsListActivity.class);
        startActivity(intent);
    }
}

3.接著,創建一個二級界面,其中重點是NavUtils的應用,可以創建任務棧

public class ItemsListActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
    private static final String[] ITEMS = {"Mon", "Dad", "Sister", "Brother", "Cousin"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_items_list);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        ListView list = new ListView(this);
        ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, ITEMS);
        list.setAdapter(adapter);
        list.setOnItemClickListener(this);
        setContentView(list);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                Intent upIntent = NavUtils.getParentActivityIntent(this);
                if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
                    TaskStackBuilder.create(this)
                            .addParentStack(this)
                            .startActivities();
                } else {
                    NavUtils.navigateUpFromSameTask(this);
                }
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        Intent intent = new Intent(this, DetailsActivity.class);
        intent.putExtra(Intent.EXTRA_TEXT, ITEMS[position]);
        startActivity(intent);

    }
}

4.創建三級界面

public class DetailsActivity extends AppCompatActivity {
private static final String ACTION_NEW_ARRIVAL="com.examples.taskstack.ACTION_NEW_ARRIVAL";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        TextView textView=new TextView(this);
        textView.setGravity(Gravity.CENTER);
        String item=getIntent().getStringExtra(Intent.EXTRA_TEXT);
        textView.setText(item);
        setContentView(textView);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                Intent upIntent = NavUtils.getParentActivityIntent(this);
                if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
                    TaskStackBuilder.create(this)
                            .addParentStack(this)
                            .startActivities();
                } else {
                    NavUtils.navigateUpFromSameTask(this);
                }
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }
}

5.AndroidManifest中配置如下,為各級設置parent,其中4.1以後不需要使用meta-data

 <activity android:name=".day20161019.RootActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".day20161019.ItemsListActivity"
            android:parentActivityName=".day20161019.RootActivity">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".day20161019.RootActivity" />
        </activity>
        <activity
            android:name=".day20161019.DetailsActivity"
            android:parentActivityName=".day20161019.ItemsListActivity">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".day20161019.ItemsListActivity" />

            <intent-filter>
                <action android:name="com.examples.taskstack.ACTION_NEW_ARRIVAL" />

                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

(七)總結

看過一個大神的博客,他說自己不覺得有多麼聰明,但別人總愛稱他是大神,可能只是因為自己在半年內看了50多本書吧,至於書該怎麼看,很簡單,敲一遍。

強,無敵。

於是閱讀《Android5.0開發範例大全》的時候,我也把部分代碼敲了一遍,很多時候怎麼看都看不懂的代碼,運行一下大多就能理解了。

不過因為個人水平太差,這文章寫出來估計沒幾個人能讀明白,實在汗顏。

接下來,我會開很多新書,繼續寫讀書筆記這個系列。

希望能多多進步吧。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...