安卓第十三天筆記-服務(Service)

来源:http://www.cnblogs.com/liunanjava/archive/2016/03/13/5225912.html
-Advertisement-
Play Games

服務 服務沒有界面,一直運行在後臺, 運行在獨立的一個進程裡面 服務沒有界面,一直運行在後臺,預設是運行當前的應用程式進程裡面。 建立一個類繼承Service類 在清單文件中註冊service   只會在開啟服務時初始化一次   每次開啟服務都會執行調用   停止服務時,只執行一次   onCrea


安卓第十三天筆記-服務(Service)

Servcie服務

1.服務概念

服務

  • windows

服務沒有界面,一直運行在後臺, 運行在獨立的一個進程裡面

  • android

服務沒有界面,一直運行在後臺,預設是運行當前的應用程式進程裡面。

2.建立服務

  • 建立一個類繼承Service類

    public class ServiceDemo extends Service {
    
  • 在清單文件中註冊service

    <service android:name="com.ithiema.servicequick.servcie.ServiceDemo"></service>

     

3.生命周期

只會在開啟服務時初始化一次

    @Override
public void onCreate() {
    //只會在開啟服務時初始化一次
    super.onCreate();
}

 

每次開啟服務都會執行調用

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    //每次開啟服務都會執行調用
    return super.onStartCommand(intent, flags, startId);
}

 

停止服務時,只執行一次

public void onDestroy() {
    //停止服務時,只執行一次
    super.onDestroy();
}

 

  • 完整生命周期

onCreate -- onStartCommand--onDestroy

  • 啟動多次服務

onCreate方法只會執行一次, 但是onStartCommand執行多次

  • 多次停止服務

只會執行一次onDestroy方法。

4.進程

Foreground process

前臺進程: 當前與用戶進行交互的應用所處的進程

  • Visible process

可見進程: 應用程式不能交互,但是界面可見。 有點類似activity生命周期的onPause

  • Service process

服務進程: 應用程式裡面運行著一個服務

  • Background process

後臺進程: 應用程式被最小化了(home)

  • Empty process

空進程:應用程式裡面沒有任何活動的組件(activity \ service)

前臺進程 > 可見進程 > 服務進程 > 後臺進程 > 空進程

5.開啟與停止服務

public void start(View v){
    startService(new Intent(this , ServiceDemo.class));
}


public void stop(View v){
    stopService(new Intent(this , ServiceDemo.class));
}

 

6.為什麼要使用服務

  1. 可以讓進程所處的優先順序有所保障。
  2. 可以長久的在後臺執行邏輯操作,即使所有的activity都銷毀了,也不影響。

場景: 1. 在後臺檢測設備接入狀況 2. 在後臺執行聯網數據請求(類似股票軟體) 3. 音樂播放器

7.綁定服務第一種

Extending the Binder class 第一種

1 先寫一個繼承Service類

2.在Service中寫一個public類繼承Binder,在這個類中寫個方法返回具服務類的對象實例

3.在onBind 中返回 這個內部類的實例

4.在service中寫幾個public的方法提供給子類調用必須為public的

 /**
     * Created by  劉楠 on 2016-02-28 14:19.
     */
    public class LocalService extends Service {
        private static final String TAG = "LocalService";
        //聲明綁定的類
        private LocalBinder mBinder = new LocalBinder();
        //給客戶端使用
        private final Random mGenerator = new Random();

        /*
        第一種繼承Binder類
         */
        public class LocalBinder extends Binder {

            public LocalService getServcie() {
                Log.d(TAG, "==getServcie==");
                return LocalService.this;
            }

        }

        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            Log.d(TAG, "==IBinder==");
            return mBinder;
        }

        @Override
        public void onCreate() {
            super.onCreate();
            Log.d(TAG, "==onCreate==");
        }


        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.d(TAG, "==onStartCommand==");
            return super.onStartCommand(intent, flags, startId);
        }

        /**
         * 返回一個隨機數
         *
         * @return
         */
        public int getRandom() {
            Log.d(TAG, "==getRandom==");
            return mGenerator.nextInt(500);
        }


        @Override
        public boolean onUnbind(Intent intent) {
            Log.d(TAG, "==onUnbind==");
            return super.onUnbind(intent);
        }

        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.d(TAG, "==onDestroy==");
        }
    }

 

5.在Manifest.xml中註冊service

 <service android:name=".serivice.LocalService"/>

6.在客戶端的Activity中綁定service bindService(intnet,ServiceConnection,Context.BINDAUTOCREATE)

7.寫一個類實現ServiceConnection介面,在方法中完成獲取Service類的實例

8.調用服務中的方法

9.解除綁定

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

    <Button
        android:onClick="bind1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="綁定服務1"/>


    <TextView
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <Button
        android:onClick="show"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="調用方法"/>

    <Button
        android:onClick="unBind"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="解綁綁定服務1"/>
</LinearLayout>

 

客戶端類

        Activity

    /**
     * 綁定服務
     */
    public class MainActivity extends AppCompatActivity {
        private static final String TAG ="MainActivity" ;
        //服務
        private LocalService mService;

        private boolean mbound = false;

        private MyServiceConnection mConection;


        private TextView tv;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Log.d(TAG, "=====MainActivity==onCreate=====");

            tv = (TextView) findViewById(R.id.tv);
        }

        /**
         * 綁定服務
         * @param view 按鍵
         */
        public void bind1(View view){
            Log.d(TAG, "=====MainActivity==bind1=====");
            Intent intent = new Intent(this,LocalService.class);

            if(mConection==null){
                mConection = new MyServiceConnection();
            }

             mbound = bindService(intent, mConection, Context.BIND_AUTO_CREATE);

            Log.d(TAG, "=====MainActivity==flag=====" + mbound);


        }

        public   void show(View v) {

            if (mbound) {
                int random = mService.getRandom();
                tv.setText(random + "");
            }

        }


        /**
         * 服務連接類
         */
        private class MyServiceConnection implements  ServiceConnection{

            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                LocalService.LocalBinder mBinder= (LocalService.LocalBinder) service;

                mService = mBinder.getServcie();
                Log.d(TAG, "=====MainActivity==MyServiceConnection==onServiceConnected===");


            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
                Log.d(TAG,"=====MainActivity==MyServiceConnection==onServiceDisconnected===");
                mbound=false;
            }
        }

        /**
         * 解除綁定
         * @param v
         */
        public  void unBind(View v){
            Log.d(TAG,"=====MainActivity==unBind======");
            if(mService!=null) {
                unbindService(mConection);
                mConection=null;

            }
        }

        /**
         * 銷毀
         */
        @Override
        protected void onDestroy() {
            Log.d(TAG,"=====MainActivity==onDestroy======");
            super.onDestroy();
            if(mService!=null&&mConection!=null) {
                unbindService(mConection);
                mConection=null;

            }
        }
    }

 

以上的方式如果只要給自己程式用同時不要把一些方法私有化的話都可以在Service中寫public的方法,使用這種方式

8.綁定服務第二種

使用Messenger與Handler的機制處理,這種方式是一種單線程的,不安全的,目前很少有人用了,會造成排隊現象

Service

    /**
 * Created by  劉楠 on 2016-02-28 16:29.
 */
public class MessengerService extends Service {

    public static final int MSG_SAY_HELLO = 1;

    Messenger mMessenger = new Messenger(new IncomingHandler());

    public class  IncomingHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){

                case MSG_SAY_HELLO:
                    Toast.makeText(getApplicationContext(),"hello Android===handleMessage==",Toast.LENGTH_SHORT).show();


            }
        }
    }

    /**
     *
     * @param intent 意圖
     * @return
     */
    @Nullable //參數可以為空
    @Override
    public IBinder onBind(Intent intent) {
        Toast.makeText(getApplicationContext(), "===onBind====", Toast.LENGTH_SHORT).show();
        return mMessenger.getBinder();
    }
}

 

清單文件

註冊
<service android:name=".service.MessengerService"/>

 

客戶端

    public class MainActivity extends AppCompatActivity {

        private Messenger mService;

        private MyServiceConnection mServiceConnection;

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

        /**
         * 界面可見時,綁定Service
         */
        @Override
        protected void onStart() {
            super.onStart();
            Intent intent = new Intent();
            intent.setClass(this, MessengerService.class);

            if(mServiceConnection==null){
                mServiceConnection = new MyServiceConnection();
            }
            //綁定
            bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
        }

        private  class  MyServiceConnection implements  ServiceConnection{


            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {


                mService = new Messenger(service);
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        }

        /**
         * 點擊事件
         * @param v
         */
        public void sayHello(View v) {

            Message msg = Message.obtain();
            msg.what=MessengerService.MSG_SAY_HELLO;
            //發送消息
            try {
                mService.send(msg);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        protected void onDestroy() {
            super.onDestroy();
            if(mService!=null&&mServiceConnection!=null) {
                unbindService(mServiceConnection);
                mServiceConnection=null;
            }
        }
    }

 

9.使用普通介面完成

  • 使用介面的方式建立Service

介面

/**
 * Created by  劉楠 on 2016-02-28 18:25.
 * 介面定義方法讓Service中自定義的Binder來實現這個介面,同時調用Service中公用與私有方法
 */
    public interface IRemoteService {

        public void display(String name,int age);

        public void gogo();

    }

 

建立Service

    /**
     * Created by  劉楠 on 2016-02-28 18:20.
     */
    public class LocalService extends Service {
        //自定義的IBinder對象
        private LocalBinder mLocalBinder= new LocalBinder();


        /**
         * 自定義的Binder
         * 對面接頭的內線
         */
        public class LocalBinder extends Binder implements IRemoteService {
            //介面的方法
            @Override
            public void display(String name, int age) {
                //調用Service中的方法
                show(name,age);
            }
            //介面的方法
            @Override
            public void gogo() {
                //調用Service中的方法
                go();
            }
            //這裡算自定義的方法
            public void showData(){
                Toast.makeText(getApplicationContext(),new Date().toString(),Toast.LENGTH_SHORT).show();
            }
        }


        private static final String TAG ="LocalService" ;

        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            Log.d(TAG,"=====onBind=======");
            return mLocalBinder;
        }

        @Override
        public void onCreate() {
            super.onCreate();
            Log.d(TAG,"=====onCreate=======");
        }

        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {

            Log.d(TAG,"=====onStartCommand=======");
            return super.onStartCommand(intent, flags, startId);
        }

        @Override
        public boolean onUnbind(Intent intent) {
            Log.d(TAG,"=====onUnbind=======");
            return super.onUnbind(intent);
        }

        @Override
        public void unbindService(ServiceConnection conn) {
            super.unbindService(conn);
            Log.d(TAG, "=====unbindService=======");
        }

        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.d(TAG, "=====onDestroy=======");
        }

        /*
                上面會調用這個方法
             */
        private void show(String name,int age){
            Toast.makeText(getApplicationContext(),"姓名:"+name+"年齡:"+age,Toast.LENGTH_SHORT).show();
            Log.d(TAG, "====service=show======");
        }

        /*
        上面的Binder會調用這個方法
         */

        private void go(){
            Toast.makeText(getApplicationContext(),"gogogogogogoggog",Toast.LENGTH_SHORT).show();
            Log.d(TAG, "====service=go======");
        }
    }

 

佈局就5個按鍵

    <?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">

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="bind"
            android:text="綁定bindService服務"/>

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="callMethod"
            android:text="調用服務中的方法"/>

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="unBind"
            android:text="解除unBindService綁定"/>

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="start"
            android:text="使用startService開始服務"/>
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="stop"
            android:text="使用stopService停止服務"/>
    </LinearLayout>

 

Activity

public class MainActivity extends AppCompatActivity {
    private static final String TGA ="MainActivity" ;
    //連接的類
    private MyServcieConnection mConnection;
    //IBinder對象
    private LocalService.LocalBinder mLocalBinder;

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




    /**
     * 綁定服務
     *
     * @param view 按鍵
     */
    public void bind(View view) {
        Log.d(TGA, "========Activity===bind======");
        Intent intent = new Intent();

        intent.setClass(this, LocalService.class);
        if(mConnection==null){
            mConnection = new MyServcieConnection();
        }
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

    /**
     * 調用服務中的方法
     *
     * @param view 按鍵
     */
    public void callMethod(View view) {
        Log.d(TGA,"========Activity===callMethod======");
        if(mLocalBinder!=null){
            //調用方法
            mLocalBinder.display("張三",18);
            mLocalBinder.gogo();
            mLocalBinder.showData();

        }
    }

    /**
     * 解除綁定服務
     *
     * @param view 按鍵
     */
    public void unBind(View view) {
        Log.d(TGA,"========Activity===unBind======");
        if(mConnection!=null){
            unbindService(mConnection);
            mConnection=null;
            mLocalBinder=null;
        }
    }

    /**
     * 開始服務
     *
     * @param view 按鍵
     */
    public void start(View view) {
        Log.d(TGA,"========Activity===start======");
        Intent intent = new Intent();
        intent.setClass(this, LocalService.class);
        startService(intent);
    }

    /**
     * 停止服務
     *
     * @param view 按鍵
     */
    public void stop(View view) {
        Log.d(TGA,"========Activity===stop======");
        //停止服務
        Intent intent = new Intent();
        intent.setClass(this, LocalService.class);
        stopService(intent);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TGA, "========Activity===onDestroy======");
       /* if(mConnection!=null){
            unbindService(mConnection);
            mConnection=null;
            mLocalBinder=null;
            return;
        }
        //停止服務
        Intent intent = new Intent();
        intent.setClass(this, LocalService.class);
        stopService(intent);*/
    }

    /**
     * 服務連接類
     */
    private class MyServcieConnection implements ServiceConnection{

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TGA,"========Activity===onServiceConnected======");
            mLocalBinder = (LocalService.LocalBinder) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d(TGA,"========Activity===onServiceDisconnected======");
        }
    }
}

 

註冊

    <!--註冊-->
    <service android:name=".service.LocalService"/>

結果:

02-28 06:39:24.895 4350-4350/? D/MainActivity: ========Activity===bind======

02-28 06:39:24.968 4350-4350/? D/LocalService: =====onCreate=======
02-28 06:39:24.969 4350-4350/? D/LocalService: =====onBind=======
02-28 06:39:24.985 4350-4350/? D/MainActivity: ========Activity===onServiceConnected======
02-28 06:39:28.625 4350-4350/? D/MainActivity: ========Activity===callMethod======

02-28 06:39:28.631 4350-4350/? D/LocalService: ====service=show======
02-28 06:39:28.637 4350-4350/? D/LocalService: ====service=go======
ace 0xeb9b54a0, error=EGL_SUCCESS
02-28 06:39:30.906 4350-4350/? D/MainActivity: ========Activity===unBind======

02-28 06:39:30.937 4350-4350/? D/LocalService: =====onUnbind=======
02-28 06:39:30.937 4350-4350/? D/LocalService: =====onDestroy=======

02-28 06:39:32.721 4350-4368/? V/RenderScript: 0xe1f0e200 Launching thread(s), CPUs 4
02-28 06:39:35.827 4350-4350/? D/MainActivity: ========Activity===start======

02-28 06:39:35.846 4350-4350/? D/LocalService: =====onCreate=======
02-28 06:39:35.846 4350-4350/? D/LocalService: =====onStartCommand=======
02-28 06:39:36.878 4350-4350/? D/MainActivity: ========Activity===stop======

02-28 06:39:36.902 4350-4350/? D/LocalService: =====onDestroy=======

 

10.AIDL (AIDL-Android Interface Definition Language)

AIDL可以同時處理多個線程的請求,並且是線程安全的.

To use AIDL directly, you must create an .aidl file that defines the programming interface. The Android SDK tools use this file to generate an abstract class that implements the interface and handles IPC, which you can then extend within your service.

要使用AIDL必須建立一個擴展名為.aidl的文件,SDK會自動生成對象的抽象類同是實現介面與Handles IPC通信,在Service中可以選擇繼承

例如:支付寶,就只是暴露了,介面給商家使用,裡面具體怎麼實現並沒有暴露

將上面的介面尾碼名改為.aidl

  • 更改Serive中的自定義IBinder

    public class LocalBinder extends IRemoteService.Stub {

  • 更改客戶端 中聲明不在寫原來的binder

       更改這個為
     private LocalService.LocalBinder mLocalBinder;
    

更改後

    //IRemoteService
    private IRemoteService mIRemoteService;

Activity

  public class MainActivity extends AppCompatActivity {
        private static final String TGA ="MainActivity" ;
        //連接的類
        private MyServcieConnection mConnection;
        //IRemoteService
        private IRemoteService mIRemoteService;

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




        /**
         * 綁定服務
         *
         * @param view 按鍵
         */
        public void bind(View view) {
            Log.d(TGA, "========Activity===bind======");
            Intent intent = new Intent();

            intent.setClass(this, LocalService.class);
            if(mConnection==null){
                mConnection = new MyServcieConnection();
            }
            bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
        }

        /**
         * 調用服務中的方法
         *
         * @param view 按鍵
         */
        public void callMethod(View view) {
            Log.d(TGA,"========Activity===callMethod======");
            if(mIRemoteService!=null){
                //調用方法
                try {
                    mIRemoteService.display("張三",18);
                    mIRemoteService.gogo();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }



            }
        }

        /**
         * 解除綁定服務
         *
         * @param view 按鍵
         */
        public void unBind(View view) {
            Log.d(TGA,"========Activity===unBind======");
            if(mConnection!=null){
                unbindService(mConnection);
                mConnection=null;
                mIRemoteService=null;
            }
        }

        /**
         * 開始服務
         *
         * @param view 按鍵
         */
        public void start(View view) {
            Log.d(TGA,"========Activity===start======");
            Intent intent = new Intent();
            intent.setClass(this, LocalService.class);
            startService(intent);
        }

        /**
         * 停止服務
         *
         * @param view 按鍵
         */
        public void stop(View view) {
            Log.d(TGA,"========Activity===stop======");
            //停止服務
            Intent intent = new Intent();
            intent.setClass(this, LocalService.class);
            stopService(intent);
        }

        @Override
        protected void onDestroy() {
            super.onDestroy();
            Log.d(TGA, "========Activity===onDestroy======");

        }

        /**
         * 服務連接類
         */
        private class MyServcieConnection implements ServiceConnection{

            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.d(TGA,"========Activity===onServiceConnected======");
                mIRemoteService =IRemoteService.Stub.asInterface(service);
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
                Log.d(TGA,"========Activity===onServiceDisconnected======");
            }
        }
    }

 

這種aidl的方式只能調用Serivce介面中的方法,不能調用Service和自定義Binder中特有的方法 常用於給第三方的應用提供服務 * 通過

 IRemoteService.Stub.asInterface(service)

 

方法得到aidl定義的介面實例

11.startService與bindService的生命周期

  • startService與stopService

startService

        onCreate---創建服務時只執行一次
        onStartCommand  ----每次開啟服務都會調用

stopService

       onDestory--停止服務時多次調用,只會執行一次

*bindService與unBindServcie

bindService

    onCreate---創建服務時只執行一次
    onBind----多次調用,只執行一次

unBindService

    onUnbind----解除時,只執行一次
    onDestory----只執行一次

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

-Advertisement-
Play Games
更多相關文章
  •   運行結果截圖:
  • 單機搭建Android開發環境二,安裝ssh、vim和samba,並配置sudo無密碼執行。
  • 由於Fragment的方便性,現在很多人開始大量使用Fragment。 今天使用時遇到各問題,記錄下來並分享下。   使用Fragment都會用FragmentActivity ,特別是在用到ViewPager時。因為需要FramgmentManager, 而我這次有兩個fragment中都用到了V
  • 工具是:JDK環境配置+SDK+ADT工具 一、Activity  主要作用: 1、用戶與應用程式的介面 2、控制項的容器 二、創建Activity要點:(在src中的目錄下包里) 1、一個Activity就是一個類,要繼承android自身的一個類 2、需要覆寫Oncreate方法,第一個運行的Ac
  • 一、Activity的簡要理解     上篇博文已經知道如何編寫一個簡單的Activity了,可能有很多初學者會疑惑到底什麼是Activity?我們來給出Activity的一個通俗的解釋:Activity就是呈現在我們手機上的各種界面,也就是說,只要在手機上我們能看到的,都是Activity。任何一
  •      圖片拉伸 lxx__lxx__lxx__lxx__lxx__lxx__lxx__lxx__lxx__lxx___ lxx__lxx__lxx__lxx__lxx__lxx__lxx__lxx__lxx__lxx___   1. 如果圖片比較大得話,不要用 [UIImage imageNam
  • 前言:這篇GCD的博文是本人閱讀了很多海內外大神的關於GCD的文章,以及結合之前自己對GCD的粗淺的認識,然後取其精華,去其槽粕,綜合起來的筆記,而且是儘可能的以通熟易懂的並且是正確的理論論述方式呈現給讀者,同時也是講大神博客中有的深澀的理論理解的通熟易懂轉述給讀者,已經是儘可能的讓讀者深入理解和掌
  • 分類:C#、Android、VS2015; 創建日期:2016-03-13 一、簡介 Android提供的Camera有兩個典型的版本,一個是在Android 5.0以前提供的,稱為Camera;另一個是從Android 5.0開始提供的,稱為Camera2。 這裡僅演示使用系統Camera程式實現...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...