最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android組件之服務(wù)的詳解

 更新時間:2021年08月30日 17:47:48   作者:Cristiano_san  
這篇文章主要詳細(xì)介紹了Android組件之一的服務(wù),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下

一、服務(wù)的概念

1、服務(wù)是實現(xiàn)程序后臺運行的解決方案,主要執(zhí)行那些不需要和用戶交互而且還要求長期運行的任務(wù)

2、服務(wù)是依賴于創(chuàng)建服務(wù)時所在的應(yīng)用程序進(jìn)程而存在的,而不是運行在一個獨立的進(jìn)程當(dāng)中

3、服務(wù)的后臺≠創(chuàng)建子線程,需要在服務(wù)的內(nèi)部手動創(chuàng)建子線程,并且在這里執(zhí)行具體的任務(wù),否則可能會出現(xiàn)主線程被堵塞的情況

二、Android的多線程編程

2.1 線程的基本用法

  • 線程聲明方式一:
	//定義方式
	class myThread extends Thread{
		  @Override
		  public void run(){
		  		//具體的處理邏輯
		  }
	}
	
	//啟動方式
	new myThread().start();
  • 線程聲明方式二:
	//定義方式
	class myThread implements Runnable{
		 @Override
		  public void run(){
		  		//具體的處理邏輯
		  }
	}
	
	//啟動方式
		myThread my = new myThread();
		new Thread(my).start();
  • 線程聲明方式三:
	new Thread(new Runnable() {
            @Override
            public void run() {

			}
	}).start();

2.2 在子線程中更新UI

更新方式一

利用runOnUiThread()方法,該方法可以要執(zhí)行的操作回調(diào)到主線程中進(jìn)行操作,使用方法:

以更新TextView為例:

	@Override
    protected void onCreate(Bundle savedInstanceState) {
        .....
        change.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        changeUI("next to meet you");
                    }
                }).start();
            }
        });
    }
    public void changeUI(String date){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                text.setText(date);
            }
        });
    }

1、我們在子線程中調(diào)用changeUI()方法,并將更改后的數(shù)據(jù)傳過去
2、在changeUI()方法中,調(diào)用runOnUiThread()方法將進(jìn)程調(diào)回到主線程中,然后調(diào)用setText()方法進(jìn)行更新UI操作

具體使用方法,博客:理解 Activity.runOnUiThread

更新方式二

利用Android自帶的異步消息處理機制

public class MainActivity extends AppCompatActivity {
    public static final int UPDATE_TEXT = 1;
    private TextView text;

    private Handler handler = new Handler(){
        public void handleMessage(Message msg){
            switch (msg.what){
                case UPDATE_TEXT:
                    //對UI進(jìn)行操作
                    text.setText("Nice to meet you");
                    break;
                default:
                    break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ....
        change.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Message message = new Message();
                        message.what = UPDATE_TEXT;
                        handler.sendMessage(message);
                    }
                }).start();
            }
        });
    }
}

1、首先定義一個字段UPDATE_TEXT表示更新的具體動作
2、創(chuàng)建Handler的對象,并重寫父類的handleMessage()方法,在該方法中對Message進(jìn)行處理
3、判斷Message的what的值,進(jìn)行相應(yīng)的UI操作
4、回到子線程,首先獲取一個Message 的對象,對what字段賦值
5、調(diào)用Handler對象的sendMessage()將這個Message 發(fā)送出去
6、在Handler收到這個消息以后就會調(diào)用handleMessage()對消息進(jìn)行處理,且現(xiàn)在已經(jīng)是在主線程中處理不會出現(xiàn)問題

2.3 解析異步消息處理機制

1、處理機制組成:Message、Handler、MessageQueue、Looper

2、Message:

  • 1)作用:在線程之間傳遞信息
  • 2)可以在內(nèi)部攜帶少量信息,利用其字段,如what,arg1,rg2,obj字段存儲,用于在不同線程之間交換數(shù)據(jù)

3、Handler:

  • 1)作用:主要用于發(fā)送和處理消息
  • 2)發(fā)送消息使用Handler的sendMessage()方法
  • 3)發(fā)出的消息經(jīng)過處理以后,傳遞到Handler的handleMessage()方法中

4、MessageQueue:

  • 1)作用:主要用于存放所有通過Handler發(fā)送的消息。每個線程中只有一個MessageQueue對象

5、Looper:

  • 1)作用:每個線程中MessageQueue的管家
  • 2)在調(diào)用其loop()方法后,進(jìn)入無限循環(huán),在循環(huán)中每發(fā)現(xiàn)MessageQueue中存在一條消息就將其取出,傳遞到Handler的handleMessage()方法中進(jìn)行處理
  • 3)每個線程中只有一個Looper對象

6、整個異步流程:

在這里插入圖片描述

  • 1)首先主線程中創(chuàng)建一個Handler的對象,并重寫父類的handleMessage()方法
  • 2)在子線程要進(jìn)行UI操作時,創(chuàng)建一個Message對象,通過Handler的sendMessage()方法出去
  • 3)這條消息會被添加到MessageQueue隊列中等待
  • 4)Looper從MessageQueue中取出一條消息,傳遞到Handler的handleMessage()方法中進(jìn)行處理

2.4 使用AsyncTask

1、AsyncTask的實現(xiàn)原理是基于異步消息處理機制的
2、AsyncTask是一個抽象類,在子類繼承這個類時指定3個泛型參數(shù):

  • Params:在執(zhí)行AsyncTask時需傳入的參數(shù),可用于在后臺任務(wù)中使用
  • Progress:后臺任務(wù)執(zhí)行時,若需要在界面上顯示當(dāng)前進(jìn)度,這里就指定的泛型作為進(jìn)度單位
  • Result:當(dāng)任務(wù)執(zhí)行完畢,若需要對結(jié)果進(jìn)行返回,則使用這里指定的泛型作為返回值類型
  • 如:
public class DownloadTask extends AsyncTask<Void,Integer,Boolean> {
    ....
}

第一個泛型參數(shù)指定為Void,表示在執(zhí)行AsyncTask時不需要傳入?yún)?shù)給后臺任務(wù)
第二個參數(shù)指定為Integer,表示使用整型數(shù)據(jù)來作為進(jìn)度顯示單位
第三個參數(shù)指定為Boolean,表示用boolean類型數(shù)據(jù)來反饋執(zhí)行結(jié)果

3、在繼承后,還需重寫如下方法

  • onPreExecute() :在后臺任務(wù)開始執(zhí)行之前調(diào)用,用于進(jìn)行一些界面上的初始化操作,如顯示一個進(jìn)度條對話框等
  • doInBackground(Params… ) :該方法中所有的代碼都會在子線程中運行。后臺任務(wù)一旦完成通過return語句將任務(wù)的執(zhí)行結(jié)果返回,若AsyncTask第三個參數(shù)指定為Void,則可以不返回任務(wù)執(zhí)行結(jié)果。若需要更新UI元素,則調(diào)用publishProgress(Progress…)方法來完成
  • onProgressUpdate(Progress… ):當(dāng)在后臺任務(wù)中調(diào)用publishProgress(Progress…)方法,該方法就會被調(diào)用,該方法所攜帶的參數(shù)就是在后臺任務(wù)中傳遞過來的,在這個方法中利用參數(shù)中的數(shù)值可以對UI進(jìn)行操作
  • onPostExecute(Result) :后臺任務(wù)執(zhí)行完畢并返回return語句進(jìn)行返回時,這個方法就會被調(diào)用,返回的數(shù)據(jù)作為參數(shù)會傳遞到此方法中,可以利用返回的數(shù)據(jù)來進(jìn)行一些UI操作,如提醒任務(wù)執(zhí)行的結(jié)果,或關(guān)閉進(jìn)度條對話框等具體框架:
		public class DownloadTask extends AsyncTask<Void,Integer,Boolean> {
		    @Override
		    protected void onPreExecute() {
		        progressDialog.show();//顯示進(jìn)度對話框
		    }
		
		    @Override
		    protected Boolean doInBackground(Void... voids) {//在該方法里執(zhí)行下載任務(wù)
		        try{
		            while(true){
		                int percent = doDownload();//虛構(gòu)一個方法,返回一個值表示下載進(jìn)度
		                publishProgress(percent);//調(diào)用publishProgress方法,并將進(jìn)度數(shù)值傳進(jìn)去
		                if(percent >= 100)
		                    break;
		            }
		        }catch (Exception e){
		            e.printStackTrace();
		        }
		        return true;
		    }
		
		    @Override
		    protected void onProgressUpdate(Integer... values) {//該方法所帶的參數(shù)就是publishProgress()方法的進(jìn)度數(shù)值
		        progressDialog.setMessage("Downloaded" + values[0] + "%");
		    }
		
		    @Override
		    protected void onPostExecute(Boolean aBoolean) {//后臺任務(wù)完成后該方法就會被調(diào)用
		        progressDialog.dismiss();//關(guān)閉進(jìn)度對話框
		        //提示下載結(jié)果
		        if (aBoolean){
		            Toast.makeText(context,"Succeeded",Toast.LENGTH_SHORT).show();
		        }else {
		            Toast.makeText(context,"Failed",Toast.LENGTH_SHORT).show();
		        }
		    }
		}

4、啟動方法:

	new DownloadTask().execute();

三、服務(wù)的基本用法

3.1 首先定義一個服務(wù)

在這里插入圖片描述

在上述界面中:Exported表示是否允許除了當(dāng)前程序之外的其他程序訪問這個服務(wù);Enabled表示是否啟動這個服務(wù)

3.2 MyService類里重寫幾個方法

	public class MyService extends Service {
	    public MyService() {
	    }
	    @Override
	    public IBinder onBind(Intent intent) {
	        // TODO: Return the communication channel to the service.
	        throw new UnsupportedOperationException("Not yet implemented");
	    }
	
	    @Override
	    public void onCreate() {
	        super.onCreate();
	    }//服務(wù)被創(chuàng)建時調(diào)用
	
	    @Override
	    public int onStartCommand(Intent intent, int flags, int startId) {
	        return super.onStartCommand(intent, flags, startId);
	    }//每次服務(wù)啟動時調(diào)用,若需要服務(wù)一旦啟動就立刻執(zhí)行某個動作,就可以將邏輯卸載這個方法里面
	
	    @Override
	    public void onDestroy() {
	        super.onDestroy();
	    }//服務(wù)被銷毀時調(diào)用
	}

1、onCreate()方法在服務(wù)被創(chuàng)建時調(diào)用
2、onStartCommand()方法在每次服務(wù)啟動時調(diào)用,若需要服務(wù)一旦啟動就立刻執(zhí)行某個動作,就可以將邏輯卸載這個方法里面
3、onDestroy()方法在服務(wù)被銷毀時調(diào)用
4、onCreate()方法在服務(wù)第一次創(chuàng)建時調(diào)用,onStartCommand()方法是在每次啟動服務(wù)時調(diào)用(若在一次服務(wù)中調(diào)用了onDestroy()方法,那么這個服務(wù)就無了,再點開始按鈕就會調(diào)用onCreate()方法)

3.3 在注冊文件中完成對服務(wù)的注冊

	<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	    package="com.example.testservices" >
	    <application
	        .....
	        <service
	            android:name=".MyService"
	            android:enabled="true"
	            android:exported="true" >
	        </service>
	        .....
	    </application>
	</manifest>

3.4 啟動和停止服務(wù)

首先要創(chuàng)建一個活動和兩個用于啟動服務(wù)的按鈕,創(chuàng)建完成后通過Intent實現(xiàn)活動和服務(wù)之間的“橋梁”搭建

		Button start = findViewById(R.id.start_service);
        Button stop = findViewById(R.id.stop_service);
        start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent startIntent = new Intent(MainActivity2.this,MyService.class);
                startService(startIntent);//啟動服務(wù)
            }
        });
        stop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent stopIntent = new Intent(MainActivity2.this,MyService.class);
                stopService(stopIntent);//停止服務(wù)
            }
        });

關(guān)于讓服務(wù)停止,如果不點擊停止按鈕服務(wù)會一直處于運行狀態(tài)??梢酝ㄟ^在MyService中指定的地方調(diào)用 stopSelf()方法 實現(xiàn)服務(wù)的自動停止

然后在MyService里定義一些日志

		public class MyService extends Service {
		    final static String TAG = "MyService";
		   	....
		    @Override
		    public void onCreate() {
		        super.onCreate();
		        Log.d(TAG,"onCreate executed");
		    }//服務(wù)被創(chuàng)建時調(diào)用
		
		    @Override
		    public int onStartCommand(Intent intent, int flags, int startId) {
		        Log.d(TAG,"onStartCommand executed");
		        return super.onStartCommand(intent, flags, startId);
		    }//每次服務(wù)啟動時調(diào)用,若需要服務(wù)一旦啟動就立刻執(zhí)行某個動作,就可以將邏輯卸載這個方法里面
		
		    @Override
		    public void onDestroy() {
		        super.onDestroy();
		        Log.d(TAG,"onDestroy executed");
		    }//服務(wù)被銷毀時調(diào)用
		}

運行結(jié)果:

在這里插入圖片描述

3.5 活動和服務(wù)進(jìn)行通信

以下載功能為例:在服務(wù)中提供一個下載功能,在活動中決定何時開始下載以及隨時查看下載進(jìn)度

1、首先在MyService中創(chuàng)建一個Binder的子類內(nèi)部類,對下載功能進(jìn)行管理:

		 class DownloadBinder extends Binder{
		        public void startDownload(){
		            Log.d(TAG,"startDownload executed");
		        }//開始下載的模擬方法
		        public int getProgress(){
		            Log.d(TAG,"getProgress executed");
		            return 0;
		        }//查看下載進(jìn)度的模擬方法
		    }

2、然后同樣地,在MyService里獲取到DownloadBinder 的實例,并且通過 onBind()方法 返回這個實例(最關(guān)鍵的一步)

 	private DownloadBinder binder = new DownloadBinder();
	.....
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return binder;
    }

3、在活動中定義兩個按鈕,分別用于綁定服務(wù)和服務(wù)解綁

4、在活動中創(chuàng)建一個ServiceConnection的匿名類,并重寫onServiceConnected()、onServiceDisconnected()方法,這兩個方法會在活動與服務(wù)成功綁定和斷開時調(diào)用

public class MainActivity2 extends AppCompatActivity {
    private MyService.DownloadBinder binder;
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            binder = (MyService.DownloadBinder) iBinder;
            binder.startDownload();
            binder.getProgress();
            //在這里通過轉(zhuǎn)型獲取到Binder實例,通過這個實例,就可以在活動中根據(jù)具體的場景來調(diào)用DownloadBinder中任何public的方法
        }
        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        .....
    }
}

5、在按鈕事件里完成活動與服務(wù)之間的綁定和解綁

 		bind.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent bindIntent = new Intent(MainActivity2.this,MyService.class);
                bindService(bindIntent,connection,BIND_AUTO_CREATE);//綁定服務(wù)
                //BIND_AUTO_CREATE是一個標(biāo)志位,該標(biāo)志位表示在活動和服務(wù)進(jìn)行綁定后自動創(chuàng)建服務(wù),即MyService里的onCreate()方法會得到執(zhí)行,onStartCommand()方法不會得到執(zhí)行
            }
        });
        unbind.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                unbindService(connection);//解除綁定
            }
        });

四、服務(wù)的生命周期

在這里插入圖片描述

在這里插入圖片描述

五、服務(wù)的更多技巧

5.1 使用前臺服務(wù)

1、前臺服務(wù)的作用:可以使服務(wù)一直保持運行狀態(tài),而不會由于系統(tǒng)內(nèi)存不足的原因?qū)е卤换厥?br /> 2、跟普通服務(wù)的區(qū)別:一直有一個正在運行的圖標(biāo)在系統(tǒng)的狀態(tài)欄顯示,下拉狀態(tài)欄后可以看到更詳細(xì)的信息
3、具體實現(xiàn):

public class MyService extends Service {
    .....
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG,"onCreate executed");
        Intent intent = new Intent(this,MainActivity2.class);
        PendingIntent pi = PendingIntent.getActivity(this,0,intent,0);
        NotificationManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
        Notification notification = new NotificationCompat.Builder(this,"YonC")
                .setContentTitle("This is content title")
                .setContentText("his is content text")
                .setWhen(System.currentTimeMillis())
                .setContentIntent(pi)
                .build();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("YonC", "YonC",NotificationManager.IMPORTANCE_HIGH);
            manager.createNotificationChannel(channel);
        }
        manager.notify(1,notification);
        startForeground(1,notification);
    }//服務(wù)被創(chuàng)建時調(diào)用
	.....
}

1、這里利用PendingIntent 和Notification 創(chuàng)建一個通知的形式創(chuàng)建了一個前臺活動
2、首先通過notify()方法將該通知顯現(xiàn)出來
3、然后調(diào)用startForeground()方法讓MyService變成一個前臺服務(wù),該方法接收兩個參數(shù),第一個參數(shù)是通知的id,
類似于notify()方法的第一個參數(shù);第二個參數(shù)為構(gòu)建出的Notification對象

4、注意還需要申請權(quán)限

	<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

5.2 服務(wù)中的多線程問題&IntentService

1、ANR:即Application Not Responding,直接在服務(wù)中處理一些耗時的邏輯就會出現(xiàn)此類情況
2、IntentService是服務(wù)的子類之一,在該類中的onHandleIntent()方法中的邏輯都是在子線程中執(zhí)行,因此可以將服務(wù)中一些耗時的邏輯都放在這個方法中從而避免ANR問題
3、具體實現(xiàn):

		public class MyIntentService extends IntentService {
		    public MyIntentService(){
		        super("MyIntentService");
		    }//這個無參的構(gòu)造函數(shù)和調(diào)用父類有參構(gòu)造函數(shù)是必須有的
		    @Override
		    protected void onHandleIntent(@Nullable Intent intent) {
		        //該方法里的邏輯都是在子線程中執(zhí)行的
		    }
		}
	 son.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(MainActivity2.this,MyIntentService.class);
                startService(intent);
            }
        });

在按鈕注冊事件中引用Intent “建橋”,再調(diào)用startService()方法開啟服務(wù)

    <service android:name=".MyIntentService"/>

完成該服務(wù)的注冊

到此這篇關(guān)于Android組件之服務(wù)的詳解的文章就介紹到這了,更多相關(guān)Android組件服務(wù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android仿微信底部實現(xiàn)Tab選項卡切換效果

    Android仿微信底部實現(xiàn)Tab選項卡切換效果

    這篇文章主要為大家介紹了Android仿微信底部實現(xiàn)Tab選項卡切換效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-02-02
  • Android自定義View展示W(wǎng)ifi信號強弱指示方法示例

    Android自定義View展示W(wǎng)ifi信號強弱指示方法示例

    這篇文章主要給大家介紹了關(guān)于Android自定義View展示W(wǎng)ifi信號強弱指示的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),文末給出了完整的實例供大家參考學(xué)習(xí),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-08-08
  • Android 自定義縮短Toast顯示時間的實例代碼

    Android 自定義縮短Toast顯示時間的實例代碼

    這篇文章主要介紹了Android 自定義縮短Toast顯示時間,本文通過實例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-01-01
  • android intent使用定義標(biāo)題

    android intent使用定義標(biāo)題

    本文將詳細(xì)介紹android怎樣自定義Intent選擇界面的標(biāo)題,提供相關(guān)參考方法
    2012-11-11
  • Android中Volley框架進(jìn)行請求網(wǎng)絡(luò)數(shù)據(jù)的使用

    Android中Volley框架進(jìn)行請求網(wǎng)絡(luò)數(shù)據(jù)的使用

    這篇文章主要介紹了Android中Volley框架進(jìn)行請求網(wǎng)絡(luò)數(shù)據(jù)的使用,本文給大家介紹的非常詳細(xì)具有參考借鑒價值,需要的朋友可以參考下
    2016-10-10
  • Android實現(xiàn)網(wǎng)易云推薦歌單界面

    Android實現(xiàn)網(wǎng)易云推薦歌單界面

    大家好,本篇文章主要講的是Android實現(xiàn)網(wǎng)易云推薦歌單界面,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-02-02
  • 關(guān)于Fragment?already?added問題的解決方案

    關(guān)于Fragment?already?added問題的解決方案

    這篇文章主要介紹了關(guān)于Fragment?already?added問題的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • Android中Fragment的基本用法示例總結(jié)

    Android中Fragment的基本用法示例總結(jié)

    Fragment是activity的界面中的一部分或一種行為,下面這篇文章主要給大家介紹了關(guān)于Android中Fragment的基本用法的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2018-05-05
  • Android?補間動畫及組合AnimationSet常用方法詳解

    Android?補間動畫及組合AnimationSet常用方法詳解

    這篇文章主要為大家介紹了Android?補間動畫及組合AnimationSet常用方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • Android自定義左右或上下滑動翻頁效果

    Android自定義左右或上下滑動翻頁效果

    這篇文章主要為大家詳細(xì)介紹了Android自定義左右或上下滑動翻頁效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-12-12

最新評論

东明县| 长岭县| 香格里拉县| 巩义市| 甘肃省| 阿克| 永靖县| 永仁县| 广东省| 温州市| 阜宁县| 兴和县| 蒙自县| 乐平市| 通化县| 织金县| 无为县| 德惠市| 石阡县| 江阴市| 勐海县| 闽侯县| 壶关县| 湖南省| 德惠市| 马山县| 黄大仙区| 丘北县| 宣化县| 禹城市| 视频| 新余市| 会理县| 乌拉特中旗| 望谟县| 家居| 浦城县| 商洛市| 开原市| 山东省| 西昌市|