2025年3月17日 星期一 甲辰(龙)年 月十六 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > 安卓(android)开发

Android C++向java传递不定长且不同类型的参数

时间:04-07来源:作者:点击数:36

1、c/c++和java之间的通信经常通过jni来实时传递参数,但是由于参数不固定或者参数类型很多需要一个合适的方法来传递。

2、这里有个实例,记录以备用,头文件

  • /*
  • * jni_tbox_observer.h
  • *
  • */
  • #ifndef JNI_TBOX_OBSERVER_H_
  • #define JNI_TBOX_OBSERVER_H_
  • #include <map>
  • #include "jni.h"
  • #ifdef HAVE_ANDROID_OS
  • #include "JNIHelp.h"
  • #endif
  • #include "tbox_interfaces.h"
  • #include "common_head.h"
  • #include "tbox_status.h"
  • namespace dls
  • {
  • using std::string;
  • class jni_tbox_observer : public tbox_observer
  • {
  • public:
  • // void on_mic_forward_changed(const u8& forward);
  • // void on_telema_business_status(const u8& business_id, const u8& status);
  • // void on_tbox_key_event(const u8& key_code, const u8& action);
  • void on_tbox_communication_state(const u8& state);
  • void on_call_status(const u8& call_status);
  • void on_tbox_reply_gps(const char *gps_info);
  • void on_test_uart_result(const u8& result);
  • jni_tbox_observer(JavaVM *jvm, JNIEnv* env, jobject obj);
  • virtual ~jni_tbox_observer();
  • private:
  • JavaVM* _jvm;
  • JNIEnv* _construct_env;
  • jobject _corresponding_jobj;
  • jclass _corresponding_jclz;
  • std::map<int, JNIEnv*> _callback_thread_JNIEnvs;
  • pthread_mutex_t _JNIEnvs_lock;
  • tbox_status* _tbox_status;
  • JNIEnv* obtain_callback_thread_env();
  • void call_java_method(const char* method_name, const char* arg_format, ...);
  • };
  • } /* namespace dls */
  • #endif /* JNI_TBOX_OBSERVER_H_ */

3、实例

  • /*
  • * jni_tbox_observer.cpp
  • *
  • */
  • #include <sys/syscall.h>
  • #include "jni_tbox_observer.h"
  • #undef LOG_TAG
  • #define LOG_TAG "TB_JNI_Observer"
  • namespace dls {
  • using std::map;
  • struct _gpsInfo {
  • u8 _gpsStatus;
  • int _gpsLongtitude;
  • int _gpsLatitude;
  • u16 _gpsSpeed;
  • u16 _gpsBearing;
  • u16 _gpsAltitude;
  • u32 _gpsTime;
  • u16 _gpsGeoDirection;
  • u8 _gpsHdop;
  • u8 _gpsVdop;
  • u8 _gpsCurTolSat;
  • u8 _gpsPosSat;
  • };
  • /** Represents SV information. */
  • struct GpsSvInfo {
  • /** Pseudo-random number for the SV. */
  • u8 prn;
  • /** Elevation of SV in degrees. */
  • u8 elevation;
  • /** Azimuth of SV in degrees. */
  • u16 azimuth;
  • /** Signal to noise ratio. */
  • u8 snr;
  • } ;
  • jni_tbox_observer::jni_tbox_observer(JavaVM *jvm, JNIEnv* env, jobject obj) :
  • _jvm(jvm), _construct_env(env), _corresponding_jobj(
  • env->NewGlobalRef(obj)), _corresponding_jclz(NULL) {
  • pthread_mutexattr_t mutex_attr;
  • pthread_mutexattr_init(&mutex_attr);
  • pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE_NP);
  • pthread_mutex_init(&_JNIEnvs_lock, &mutex_attr);
  • jclass clz = env->GetObjectClass(_corresponding_jobj);
  • _corresponding_jclz = reinterpret_cast<jclass>(env->NewGlobalRef(clz));
  • _tbox_status = new tbox_status();
  • }
  • jni_tbox_observer::~jni_tbox_observer() {
  • _construct_env->DeleteGlobalRef(_corresponding_jobj);
  • _construct_env->DeleteGlobalRef(_corresponding_jclz);
  • for (map<int, JNIEnv*>::iterator it = _callback_thread_JNIEnvs.begin();
  • it != _callback_thread_JNIEnvs.end(); it++) {
  • //XXX How To detach current thread JNI environment???? OMG, I don't know, fortunately we needn't to do so.
  • }
  • _callback_thread_JNIEnvs.clear();
  • }
  • /*
  • void jni_tbox_observer::on_mic_forward_changed(const u8& forward) {
  • call_java_method("onMicForwardFromNative", "(I)V", forward);
  • }
  • void jni_tbox_observer::on_telema_business_status(const u8& business_id,
  • const u8& status) {
  • call_java_method("onTelematicBusinessStatusFromNative", "(II)V",
  • business_id, status);
  • }
  • void jni_tbox_observer::on_tbox_key_event(const u8& key_code,
  • const u8& action) {
  • call_java_method("onTBoxKeyEventFromNative", "(II)V", key_code, action);
  • }
  • */
  • void jni_tbox_observer::on_tbox_communication_state(const u8& state) {
  • call_java_method("onTBoxCommunicationState", "(I)V", state);
  • }
  • void jni_tbox_observer::on_call_status(const u8& call_status) {
  • call_java_method("onCallStatusResponse", "(I)V", call_status);
  • }
  • void jni_tbox_observer::on_test_uart_result(const u8& result) {
  • call_java_method("onTestUartResponse", "(I)V", result);
  • }
  • u32 EndianConvertLToB(u32 InputNum) {
  • u8 *p = (u8*)&InputNum;
  • return(((u32)*p<<24)+((u32)*(p+1)<<16)+
  • ((u32)*(p+2)<<8)+(u32)*(p+3));
  • }
  • u16 EndianConvertLToBS(u16 InputNum) {
  • u8 *p = (u8*)&InputNum;
  • return(((u16)*p<<8)+((u16)*(p+1)));
  • }
  • GpsSvInfo getSVInfo(const char *gInfo) {
  • struct GpsSvInfo mGi;
  • mGi.prn = *gInfo;
  • mGi.elevation = *(gInfo+1);
  • mGi.azimuth = *(u16 *)(gInfo+2);
  • mGi.azimuth = EndianConvertLToBS(mGi.azimuth);
  • mGi.snr = *(gInfo+4);
  • return mGi;
  • }
  • void jni_tbox_observer::on_tbox_reply_gps(const char * gps_info) {
  • struct _gpsInfo gI;
  • struct GpsSvInfo GSI1;
  • struct GpsSvInfo GSI2;
  • struct GpsSvInfo GSI3;
  • struct GpsSvInfo GSI4;
  • struct GpsSvInfo GSI5;
  • struct GpsSvInfo GSI6;
  • struct GpsSvInfo GSI7;
  • struct GpsSvInfo GSI8;
  • struct GpsSvInfo GSI9;
  • struct GpsSvInfo GSI10;
  • struct GpsSvInfo GSI11;
  • struct GpsSvInfo GSI12;
  • gI._gpsStatus = *gps_info;
  • gI._gpsLongtitude = *(int *)(gps_info+1);
  • gI._gpsLongtitude =(int) EndianConvertLToB(gI._gpsLongtitude);
  • gI._gpsLatitude = *(int *)(gps_info+5);
  • gI._gpsLatitude =(int) EndianConvertLToB(gI._gpsLatitude);
  • gI._gpsSpeed = *(u16 *)(gps_info+9);
  • gI._gpsSpeed = EndianConvertLToBS(gI._gpsSpeed);
  • gI._gpsBearing = *(u16 *)(gps_info+11);
  • gI._gpsBearing = EndianConvertLToBS(gI._gpsBearing);
  • gI._gpsAltitude = *(u16 *)(gps_info+13);
  • gI._gpsAltitude = EndianConvertLToBS(gI._gpsAltitude);
  • gI._gpsTime = *(u32 *)(gps_info+15);
  • gI._gpsTime =(u32) EndianConvertLToB(gI._gpsTime);
  • gI._gpsGeoDirection = *(u16 *)(gps_info+19);
  • gI._gpsGeoDirection = EndianConvertLToBS(gI._gpsGeoDirection);
  • gI._gpsHdop = *(gps_info+21);
  • gI._gpsVdop = *(gps_info+22);
  • gI._gpsCurTolSat = *(gps_info+23);
  • gI._gpsPosSat = *(gps_info+24);
  • /*LOGD("################# gI->_gpsStatus[%d]\n",gI._gpsStatus);
  • LOGD("################# gI->_gpsLongtitude[%ul],[0x%x]\n",gI._gpsLongtitude,gI._gpsLongtitude);
  • LOGD("################# gI->_gpsLatitude[%ul],[0x%x]\n",gI._gpsLatitude,gI._gpsLatitude);
  • LOGD("################# gI->_gpsSpeed[%d]\n",gI._gpsSpeed);
  • LOGD("################# gI->_gpsBearing[%d]\n",gI._gpsBearing);
  • LOGD("################# gI->_gpsAltitude[%d]\n",gI._gpsAltitude);
  • LOGD("################# gI->_gpsTime[%ul],[0x%x]\n",gI._gpsTime,gI._gpsTime);
  • LOGD("################# gI->_gpsGeoDirection[%d]\n",gI._gpsGeoDirection);
  • LOGD("################# gI->_gpsHdop[%d]\n",gI._gpsHdop);
  • LOGD("################# gI->_gpsVdop[%d]\n",gI._gpsVdop);
  • LOGD("################# gI->_gpsCurTolSat[%d]\n",gI._gpsCurTolSat);
  • LOGD("################# gI->_gpsPosSat[%d]\n",gI._gpsPosSat);*/
  • GSI1 = getSVInfo((gps_info+25));
  • GSI2 = getSVInfo((gps_info+30));
  • GSI3 = getSVInfo((gps_info+35));
  • GSI4 = getSVInfo((gps_info+40));
  • GSI5 = getSVInfo((gps_info+45));
  • GSI6 = getSVInfo((gps_info+50));
  • GSI7 = getSVInfo((gps_info+55));
  • GSI8 = getSVInfo((gps_info+60));
  • GSI9 = getSVInfo((gps_info+65));
  • GSI10 = getSVInfo((gps_info+70));
  • GSI11 = getSVInfo((gps_info+75));
  • GSI12 = getSVInfo((gps_info+80));
  • _tbox_status->gps_status = gI._gpsStatus;
  • _tbox_status->gps_longitude = gI._gpsLongtitude;
  • _tbox_status->gps_latitude = gI._gpsLatitude;
  • _tbox_status->gps_speed = gI._gpsSpeed;
  • _tbox_status->gps_Bearing = gI._gpsBearing;
  • _tbox_status->gps_altitude = gI._gpsAltitude;
  • _tbox_status->gps_time = gI._gpsTime;
  • _tbox_status->gps_geo_direction = gI._gpsGeoDirection;
  • _tbox_status->gps_hdop = gI._gpsHdop;
  • _tbox_status->gps_vdop = gI._gpsVdop;
  • _tbox_status->gps_cur_tol_sat = gI._gpsCurTolSat;
  • _tbox_status->gps_pos_sat = gI._gpsPosSat;
  • call_java_method("onTBoxReplyGPSInfo", "(IIISSSISIIIIIISIIISIIISIIISIIISIIISIIISIIISIIISIIISIIISIIISI)V", gI._gpsStatus,gI._gpsLongtitude,gI._gpsLatitude,gI._gpsSpeed,gI._gpsBearing,
  • gI._gpsAltitude,gI._gpsTime,gI._gpsGeoDirection,gI._gpsHdop,gI._gpsVdop,gI._gpsCurTolSat,gI._gpsPosSat,
  • GSI1.prn,GSI1.elevation,GSI1.azimuth,GSI1.snr,
  • GSI2.prn,GSI2.elevation,GSI2.azimuth,GSI2.snr,
  • GSI3.prn,GSI3.elevation,GSI3.azimuth,GSI3.snr,
  • GSI4.prn,GSI4.elevation,GSI4.azimuth,GSI4.snr,
  • GSI5.prn,GSI5.elevation,GSI5.azimuth,GSI5.snr,
  • GSI6.prn,GSI6.elevation,GSI6.azimuth,GSI6.snr,
  • GSI7.prn,GSI7.elevation,GSI7.azimuth,GSI7.snr,
  • GSI8.prn,GSI8.elevation,GSI8.azimuth,GSI8.snr,
  • GSI9.prn,GSI9.elevation,GSI9.azimuth,GSI9.snr,
  • GSI10.prn,GSI10.elevation,GSI10.azimuth,GSI10.snr,
  • GSI11.prn,GSI11.elevation,GSI11.azimuth,GSI11.snr,
  • GSI12.prn,GSI12.elevation,GSI12.azimuth,GSI12.snr);
  • }
  • void jni_tbox_observer::call_java_method(const char* method_name,
  • const char* arg_format, ...) {
  • JNIEnv* env = obtain_callback_thread_env();
  • va_list args;
  • jmethodID method = env->GetMethodID(_corresponding_jclz, method_name,
  • arg_format);
  • if (method) {
  • va_start(args, arg_format);
  • env->CallVoidMethodV(_corresponding_jobj, method, args);
  • va_end(args);
  • } else {
  • LOGW(
  • "Can't call Java method name[%s], arg_format[%s]", method_name, arg_format);
  • }
  • }
  • JNIEnv* jni_tbox_observer::obtain_callback_thread_env() {
  • JNIEnv* env = NULL;
  • #ifdef HAVE_ANDROID_OS
  • int tid = gettid();
  • #else
  • int tid = syscall(SYS_gettid);
  • #endif
  • map<int, JNIEnv*>::iterator it = _callback_thread_JNIEnvs.find(tid);
  • if (it == _callback_thread_JNIEnvs.end() || it->second == NULL) {
  • LOGW("Not Found JNIEnv For Thread[%d] In The <Tid, JNIEnv> Map", tid);
  • #ifdef HAVE_ANDROID_OS
  • _jvm->AttachCurrentThread(&env, NULL);
  • #else
  • _jvm->AttachCurrentThread((void**) &env, NULL);
  • #endif //HAVE_ANDROID_OS
  • _callback_thread_JNIEnvs[tid] = env;
  • } else {
  • env = it->second;
  • }
  • return env;
  • }
  • } /* namespace dls */

4、java实例

  • /** Parameters
  • *
  • * gpsStatus 定位状态
  • * gpsLongitude 经度
  • * gpsLatitude 纬度
  • * gpsSpeed 速度
  • * gpsBearing 方向
  • * gpsAltitude 高度
  • * gpsTimeStamp 时间
  • * gpsGeoDirection 地磁方向
  • * gpsHdop HDOP
  • * gpsVdop VDOP
  • * gpsCurTolSat 当前卫星总数
  • * gpsPosSat 用于定位的卫星数
  • *
  • */
  • private int gpsStatus;
  • private double gpsLongitude = TBoxManager.DEFAULT_VALUE_LONG_LAT;
  • private double gpsLatitude = TBoxManager.DEFAULT_VALUE_LONG_LAT;
  • private float gpsSpeed;
  • private float gpsBearing = TBoxManager.DEFAULT_VALUE_BEARING;
  • private float gpsAltitude;
  • private long gpsTimeStamp;
  • private float gpsGeoDirection;
  • private float gpsHdop;
  • private float gpsVdop;
  • private int gpsCurTolSat;
  • private int gpsPosSat;
  • private float m_sv1_azimuth;
  • private float m_sv2_azimuth;
  • private float m_sv3_azimuth;
  • private float m_sv4_azimuth;
  • private float m_sv5_azimuth;
  • private float m_sv6_azimuth;
  • private float m_sv7_azimuth;
  • private float m_sv8_azimuth;
  • private float m_sv9_azimuth;
  • private float m_sv10_azimuth;
  • private float m_sv11_azimuth;
  • private float m_sv12_azimuth;
  • private void onTBoxReplyGPSInfo(int gI_status, int gI_longitude, int gI_latitude, short gI_speed, short gI_Bearing,short gI_Altitude, int gI_TimeStamp,
  • short gI_geo_direction, int gI_Hdop, int gI_Vdop, int gI_cur_tol_sat, int gI_pos_sat,
  • int sv1_prn,int sv1_elevation,short sv1_azimuth,int sv1_snr,
  • int sv2_prn,int sv2_elevation,short sv2_azimuth,int sv2_snr,
  • int sv3_prn,int sv3_elevation,short sv3_azimuth,int sv3_snr,
  • int sv4_prn,int sv4_elevation,short sv4_azimuth,int sv4_snr,
  • int sv5_prn,int sv5_elevation,short sv5_azimuth,int sv5_snr,
  • int sv6_prn,int sv6_elevation,short sv6_azimuth,int sv6_snr,
  • int sv7_prn,int sv7_elevation,short sv7_azimuth,int sv7_snr,
  • int sv8_prn,int sv8_elevation,short sv8_azimuth,int sv8_snr,
  • int sv9_prn,int sv9_elevation,short sv9_azimuth,int sv9_snr,
  • int sv10_prn,int sv10_elevation,short sv10_azimuth,int sv10_snr,
  • int sv11_prn,int sv11_elevation,short sv11_azimuth,int sv11_snr,
  • int sv12_prn,int sv12_elevation,short sv12_azimuth,int sv12_snr) {
  • int mOldState = mConmmuincationState;
  • if(mOldState == COMMUNICATION_DISCONNECTED || mOldState == COMMUNICATION_UNKNOWN) {
  • mConmmuincationState = COMMUNICATION_ESTABLISHED;
  • }
  • gpsStatus = gI_status;
  • gpsLongitude = (double) (gI_longitude / 100000.0);
  • gpsLatitude = (double) (gI_latitude / 100000.0);
  • gpsSpeed = (float) (gI_speed / 100.0);
  • gpsBearing = (float) (gI_Bearing / 100.0);
  • gpsAltitude = (float) gI_Altitude;
  • gpsTimeStamp = (long) gI_TimeStamp;
  • gpsGeoDirection = (float) (gI_geo_direction / 100.0);
  • gpsHdop = (float) (gI_Hdop / 10.0);
  • gpsVdop = (float) (gI_Vdop / 10.0);
  • gpsCurTolSat = gI_cur_tol_sat;
  • gpsPosSat = gI_pos_sat;
  • m_sv1_azimuth = (float) (sv1_azimuth / 1.0);
  • m_sv2_azimuth = (float) (sv2_azimuth / 1.0);
  • m_sv3_azimuth = (float) (sv3_azimuth / 1.0);
  • m_sv4_azimuth = (float) (sv4_azimuth / 1.0);
  • m_sv5_azimuth = (float) (sv5_azimuth / 1.0);
  • m_sv6_azimuth = (float) (sv6_azimuth / 1.0);
  • m_sv7_azimuth = (float) (sv7_azimuth / 1.0);
  • m_sv8_azimuth = (float) (sv8_azimuth / 1.0);
  • m_sv9_azimuth = (float) (sv9_azimuth / 1.0);
  • m_sv10_azimuth = (float) (sv10_azimuth / 1.0);
  • m_sv11_azimuth = (float) (sv11_azimuth / 1.0);
  • m_sv12_azimuth = (float) (sv12_azimuth / 1.0);
  • /*
  • LOGD("######################### onTBoxReportGPSInfo == " + "\n" +
  • " gpsStatus == " + gpsStatus + "\n" +
  • " gpsLongitude == " + gpsLongitude + "\n" +
  • " gpsLatitude == " + gpsLatitude + "\n" +
  • " gpsSpeed == " + gpsSpeed + "\n" +
  • " gpsBearing == " + gpsBearing + "\n" +
  • " gpsAltitude == " + gpsAltitude + "\n" +
  • " gpsTimeStamp == " + gpsTimeStamp + "\n" +
  • " gpsGeoDirection == " + gpsGeoDirection + "\n" +
  • " gpsHdop == " + gpsHdop + "\n" +
  • " gpsVdop == " + gpsVdop + "\n" +
  • " gpsCurTolSat == " + gpsCurTolSat + "\n" +
  • " gpsPosSat == " + gpsPosSat + "\n"
  • + " prn 1: " + sv1_prn + " elevation 1: " +sv1_elevation + " azimuth 1: " +sv1_azimuth + " snr 1: " +sv1_snr + "\n"
  • + " prn 2: " + sv2_prn + " elevation 2: " +sv2_elevation + " azimuth 2: " +sv2_azimuth + " snr 2: " +sv2_snr + "\n"
  • + " prn 3: " + sv3_prn + " elevation 3: " +sv3_elevation + " azimuth 3: " +sv3_azimuth + " snr 3: " +sv3_snr + "\n"
  • + " prn 4: " + sv4_prn + " elevation 4: " +sv4_elevation + " azimuth 4: " +sv4_azimuth + " snr 4: " +sv4_snr + "\n"
  • + " prn 5: " + sv5_prn + " elevation 5: " +sv5_elevation + " azimuth 5: " +sv5_azimuth + " snr 5: " +sv5_snr + "\n"
  • + " prn 6: " + sv6_prn + " elevation 6: " +sv6_elevation + " azimuth 6: " +sv6_azimuth + " snr 6: " +sv6_snr + "\n"
  • + " prn 7: " + sv7_prn + " elevation 7: " +sv7_elevation + " azimuth 7: " +sv7_azimuth + " snr 7: " +sv7_snr + "\n"
  • + " prn 8: " + sv8_prn + " elevation 8: " +sv8_elevation + " azimuth 8: " +sv8_azimuth + " snr 8: " +sv8_snr + "\n"
  • + " prn 9: " + sv9_prn + " elevation 9: " +sv9_elevation + " azimuth 9: " +sv9_azimuth + " snr 9: " +sv9_snr + "\n"
  • + " prn 10: " + sv10_prn + " elevation 10: " +sv10_elevation + " azimuth 10: " +sv10_azimuth + " snr 10: " +sv10_snr + "\n"
  • + " prn 11: " + sv11_prn + " elevation 11: " +sv11_elevation + " azimuth 11: " +sv11_azimuth + " snr 11: " +sv11_snr + "\n"
  • + " prn 12: " + sv12_prn + " elevation 12: " +sv12_elevation + " azimuth 12: " +sv12_azimuth + " snr 12: " +sv12_snr);
  • */
  • if(mReportGpsFlag){
  • setGPSInfoDataSource(gpsStatus, gpsLongitude, gpsLatitude, gpsSpeed, gpsBearing, gpsAltitude,
  • gpsTimeStamp, gpsGeoDirection, gpsHdop, gpsVdop, gpsCurTolSat, gpsPosSat,
  • sv1_prn, sv1_elevation, m_sv1_azimuth, sv1_snr,
  • sv2_prn, sv2_elevation, m_sv2_azimuth, sv2_snr,
  • sv3_prn, sv3_elevation, m_sv3_azimuth, sv3_snr,
  • sv4_prn, sv4_elevation, m_sv4_azimuth, sv4_snr,
  • sv5_prn, sv5_elevation, m_sv5_azimuth, sv5_snr,
  • sv6_prn, sv6_elevation, m_sv6_azimuth, sv6_snr,
  • sv7_prn, sv7_elevation, m_sv7_azimuth, sv7_snr,
  • sv8_prn, sv8_elevation, m_sv8_azimuth, sv8_snr,
  • sv9_prn, sv9_elevation, m_sv9_azimuth, sv9_snr,
  • sv10_prn, sv10_elevation, m_sv10_azimuth, sv10_snr,
  • sv11_prn, sv11_elevation, m_sv11_azimuth, sv11_snr,
  • sv12_prn, sv12_elevation, m_sv12_azimuth, sv12_snr);
  • //Broadcast the GPS time when the GPS status is ok.
  • if(gpsStatus == 1 && mReportTimeFlag) {
  • LOGD("Broadcast the GPS time stamps");
  • mReportTimeFlag = false;
  • //Intent i = new Intent(TBoxManager.ACTION_TBOX_GPS_TIME);
  • Date date;
  • long tempTime = gpsTimeStamp * 1000;
  • date = new Date(tempTime);
  • LOGD("sendBroadcast the Current time is: " + date);
  • //i.putExtra(TBoxManager.EXTRA_TBOX_GPS_TIME, tempTime);
  • //LOGD("sendBroadcast intent: " + i.toURI());
  • //mContext.sendBroadcast(i);
  • Bundle bundle = new Bundle();
  • bundle.putLong(TBoxManager.EXTRA_TBOX_GPS_TIME, tempTime);
  • broadcastTBoxEvent(TBoxManager.ACTION_TBOX_GPS_TIME, bundle);
  • }
  • }
  • }
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门