当前位置: 首页 > wzjs >正文

搭建视频播放网站表白网站是怎么做的

搭建视频播放网站,表白网站是怎么做的,深圳鸿天顺网站建设,建站教程下载BroadcastReceiver的应用 本文是Android四大组件系列的第四篇,主要介绍BroadcastReceiver的基本概念、使用方式以及实际应用场景。 一、BroadcastReceiver基础概念 BroadcastReceiver(广播接收器)是Android四大组件之一,主要用于…

BroadcastReceiver的应用

本文是Android四大组件系列的第四篇,主要介绍BroadcastReceiver的基本概念、使用方式以及实际应用场景。

一、BroadcastReceiver基础概念

BroadcastReceiver(广播接收器)是Android四大组件之一,主要用于接收和响应系统或应用发出的广播消息。它允许应用程序接收来自Android系统或其他应用程序的通知,从而实现组件间的松耦合通信。

1.1 BroadcastReceiver的特点

  • 松耦合通信:发送方和接收方无需直接关联,通过Intent进行通信
  • 全局事件处理:可以接收系统级别的广播事件,如开机启动、网络变化等
  • 跨应用通信:可以接收来自其他应用的广播消息
  • 生命周期短:广播接收器只在处理广播消息时激活,处理完成后即销毁

1.2 广播的分类

按发送方式分类
  • 标准广播(Normal Broadcast):完全异步,所有接收器几乎同时接收到广播
  • 有序广播(Ordered Broadcast):按照优先级顺序传递,前面的接收器可以截断广播
按注册方式分类
  • 静态注册:在AndroidManifest.xml中注册,应用未启动时也能接收广播
  • 动态注册:在代码中注册,随组件生命周期变化,需要手动注销
按作用范围分类
  • 系统广播:由Android系统发出的广播,如开机、电量变化等
  • 应用内广播:在应用内部发送和接收的广播
  • 跨应用广播:可以被其他应用接收的广播

二、BroadcastReceiver的使用方式

2.1 创建BroadcastReceiver

创建BroadcastReceiver需要继承BroadcastReceiver类并实现onReceive()方法:

public class MyReceiver extends BroadcastReceiver {private static final String TAG = "MyReceiver";@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();Log.d(TAG, "Received broadcast: " + action);// 获取广播中的数据String data = intent.getStringExtra("data");// 处理广播消息if ("com.example.MY_ACTION".equals(action)) {// 处理自定义广播Toast.makeText(context, "Received: " + data, Toast.LENGTH_SHORT).show();} else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {// 处理系统广播Log.d(TAG, "System boot completed");}}
}

2.2 静态注册BroadcastReceiver

在AndroidManifest.xml中注册广播接收器:

<receiverandroid:name=".MyReceiver"android:exported="true"><intent-filter><!-- 自定义广播 --><action android:name="com.example.MY_ACTION" /><!-- 系统广播 --><action android:name="android.intent.action.BOOT_COMPLETED" /></intent-filter>
</receiver>

注意:从Android 8.0(API级别26)开始,大多数隐式广播(没有明确指定接收器的广播)无法通过静态注册的方式接收,需要使用动态注册。

2.3 动态注册BroadcastReceiver

在代码中动态注册和注销广播接收器:

public class MainActivity extends AppCompatActivity {private MyReceiver myReceiver;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 创建广播接收器实例myReceiver = new MyReceiver();}@Overrideprotected void onStart() {super.onStart();// 注册广播接收器IntentFilter filter = new IntentFilter();filter.addAction("com.example.MY_ACTION");filter.addAction(Intent.ACTION_BATTERY_LOW);registerReceiver(myReceiver, filter);}@Overrideprotected void onStop() {super.onStop();// 注销广播接收器unregisterReceiver(myReceiver);}
}

2.4 发送广播

发送标准广播
// 创建Intent对象
Intent intent = new Intent("com.example.MY_ACTION");// 添加数据
intent.putExtra("data", "Hello Broadcast");// 发送广播
sendBroadcast(intent);
发送有序广播
// 创建Intent对象
Intent intent = new Intent("com.example.MY_ORDERED_ACTION");// 添加数据
intent.putExtra("data", "Hello Ordered Broadcast");// 发送有序广播
sendOrderedBroadcast(intent, null); // 第二个参数是权限

2.5 本地广播(LocalBroadcastManager)

本地广播只在应用内部传递,更加安全高效:

// 创建LocalBroadcastManager实例
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);// 注册本地广播接收器
IntentFilter filter = new IntentFilter("com.example.LOCAL_ACTION");
localBroadcastManager.registerReceiver(myReceiver, filter);// 发送本地广播
Intent intent = new Intent("com.example.LOCAL_ACTION");
intent.putExtra("data", "Hello Local Broadcast");
localBroadcastManager.sendBroadcast(intent);// 注销本地广播接收器
localBroadcastManager.unregisterReceiver(myReceiver);

注意:LocalBroadcastManager已在AndroidX中被废弃,推荐使用LiveData、Flow或其他替代方案。

三、实战案例:网络状态监听

3.1 创建网络状态广播接收器

public class NetworkReceiver extends BroadcastReceiver {private NetworkCallback networkCallback;public interface NetworkCallback {void onNetworkChanged(boolean isConnected, String networkType);}public NetworkReceiver(NetworkCallback callback) {this.networkCallback = callback;}@Overridepublic void onReceive(Context context, Intent intent) {if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {// 检查网络连接状态boolean isConnected = false;String networkType = "unknown";ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);NetworkInfo activeNetwork = cm.getActiveNetworkInfo();if (activeNetwork != null && activeNetwork.isConnected()) {isConnected = true;if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI) {networkType = "WiFi";} else if (activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) {networkType = "Mobile";}}// 通知回调if (networkCallback != null) {networkCallback.onNetworkChanged(isConnected, networkType);}}}
}

3.2 在Activity中使用网络状态监听

public class MainActivity extends AppCompatActivity implements NetworkReceiver.NetworkCallback {private NetworkReceiver networkReceiver;private TextView networkStatusText;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);networkStatusText = findViewById(R.id.network_status);// 创建网络状态接收器networkReceiver = new NetworkReceiver(this);}@Overrideprotected void onStart() {super.onStart();// 注册网络状态接收器IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);registerReceiver(networkReceiver, filter);// 立即检查当前网络状态checkNetworkStatus();}@Overrideprotected void onStop() {super.onStop();// 注销网络状态接收器unregisterReceiver(networkReceiver);}@Overridepublic void onNetworkChanged(boolean isConnected, String networkType) {// 更新UI显示网络状态if (isConnected) {networkStatusText.setText("Connected to " + networkType);networkStatusText.setTextColor(Color.GREEN);} else {networkStatusText.setText("No network connection");networkStatusText.setTextColor(Color.RED);}}private void checkNetworkStatus() {ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);NetworkInfo activeNetwork = cm.getActiveNetworkInfo();boolean isConnected = activeNetwork != null && activeNetwork.isConnected();String networkType = "unknown";if (isConnected) {if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI) {networkType = "WiFi";} else if (activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) {networkType = "Mobile";}}onNetworkChanged(isConnected, networkType);}
}

3.3 适配Android 7.0及以上版本

Android 7.0(API级别24)及以上版本对广播接收器有一些限制,特别是对于系统广播。对于网络状态监听,可以使用NetworkCallback替代广播接收器:

public class NetworkMonitor {private ConnectivityManager connectivityManager;private NetworkCallback networkCallback;public interface NetworkStatusCallback {void onNetworkAvailable();void onNetworkLost();}public NetworkMonitor(Context context, final NetworkStatusCallback callback) {connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {// 使用NetworkCallback(Android 7.0及以上)networkCallback = new ConnectivityManager.NetworkCallback() {@Overridepublic void onAvailable(Network network) {if (callback != null) {callback.onNetworkAvailable();}}@Overridepublic void onLost(Network network) {if (callback != null) {callback.onNetworkLost();}}};}}public void register() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {// 注册NetworkCallbackNetworkRequest request = new NetworkRequest.Builder().build();connectivityManager.registerNetworkCallback(request, networkCallback);}}public void unregister() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && networkCallback != null) {// 注销NetworkCallbackconnectivityManager.unregisterNetworkCallback(networkCallback);}}
}

四、常见系统广播及应用场景

4.1 系统启动相关广播

  • ACTION_BOOT_COMPLETED:系统启动完成
    • 应用场景:启动后台服务、初始化应用数据
    • 权限要求:需要RECEIVE_BOOT_COMPLETED权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
  • ACTION_SHUTDOWN:系统关机
    • 应用场景:保存重要数据、释放资源

4.2 电源管理相关广播

  • ACTION_BATTERY_LOW:电池电量低

    • 应用场景:提醒用户、降低应用耗电
  • ACTION_BATTERY_OKAY:电池电量恢复正常

    • 应用场景:恢复正常功能
  • ACTION_POWER_CONNECTED:连接电源

    • 应用场景:开始执行耗电任务
  • ACTION_POWER_DISCONNECTED:断开电源

    • 应用场景:停止耗电任务、进入省电模式

4.3 网络相关广播

  • CONNECTIVITY_ACTION:网络连接状态变化

    • 应用场景:监控网络状态、调整应用行为
    • 注意:Android 7.0后需要动态注册
  • WIFI_STATE_CHANGED_ACTION:WiFi状态变化

    • 应用场景:监控WiFi开关状态

4.4 应用安装相关广播

  • ACTION_PACKAGE_ADDED:应用安装

    • 应用场景:监控新应用安装
  • ACTION_PACKAGE_REMOVED:应用卸载

    • 应用场景:清理相关数据
  • ACTION_PACKAGE_REPLACED:应用更新

    • 应用场景:检测应用更新,执行迁移操作

五、实战案例:应用内消息推送系统

5.1 创建消息广播发送器

public class MessagePushManager {private static final String ACTION_NEW_MESSAGE = "com.example.ACTION_NEW_MESSAGE";private Context context;public MessagePushManager(Context context) {this.context = context.getApplicationContext();}public void sendMessage(String title, String content, String targetScreen) {Intent intent = new Intent(ACTION_NEW_MESSAGE);intent.putExtra("title", title);intent.putExtra("content", content);intent.putExtra("target_screen", targetScreen);intent.putExtra("timestamp", System.currentTimeMillis());// 使用LocalBroadcastManager发送应用内广播LocalBroadcastManager.getInstance(context).sendBroadcast(intent);}
}

5.2 创建消息广播接收器

public class MessageReceiver extends BroadcastReceiver {private static final String ACTION_NEW_MESSAGE = "com.example.ACTION_NEW_MESSAGE";private MessageListener listener;public interface MessageListener {void onNewMessage(String title, String content, String targetScreen, long timestamp);}public MessageReceiver(MessageListener listener) {this.listener = listener;}public static IntentFilter getIntentFilter() {return new IntentFilter(ACTION_NEW_MESSAGE);}@Overridepublic void onReceive(Context context, Intent intent) {if (ACTION_NEW_MESSAGE.equals(intent.getAction()) && listener != null) {String title = intent.getStringExtra("title");String content = intent.getStringExtra("content");String targetScreen = intent.getStringExtra("target_screen");long timestamp = intent.getLongExtra("timestamp", 0);listener.onNewMessage(title, content, targetScreen, timestamp);}}
}

5.3 在Activity中使用消息系统

public class MainActivity extends AppCompatActivity implements MessageReceiver.MessageListener {private MessageReceiver messageReceiver;private MessagePushManager pushManager;private TextView messageView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);messageView = findViewById(R.id.message_view);pushManager = new MessagePushManager(this);messageReceiver = new MessageReceiver(this);// 发送测试消息按钮findViewById(R.id.btn_send_message).setOnClickListener(v -> {pushManager.sendMessage("测试标题", "这是一条测试消息内容", "MainActivity");});}@Overrideprotected void onStart() {super.onStart();// 注册消息接收器LocalBroadcastManager.getInstance(this).registerReceiver(messageReceiver, MessageReceiver.getIntentFilter());}@Overrideprotected void onStop() {super.onStop();// 注销消息接收器LocalBroadcastManager.getInstance(this).unregisterReceiver(messageReceiver);}@Overridepublic void onNewMessage(String title, String content, String targetScreen, long timestamp) {// 处理接收到的消息if ("MainActivity".equals(targetScreen) || targetScreen == null) {String formattedTime = new SimpleDateFormat("HH:mm:ss", Locale.getDefault()).format(new Date(timestamp));String message = String.format("[%s] %s\n%s", formattedTime, title, content);messageView.append(message + "\n\n");// 自动滚动到底部final ScrollView scrollView = (ScrollView) messageView.getParent();scrollView.post(() -> scrollView.fullScroll(View.FOCUS_DOWN));}}
}

六、常见面试题解析

6.1 BroadcastReceiver相关面试题

问题1:BroadcastReceiver的两种注册方式有什么区别?

答案

  1. 静态注册

    • 在AndroidManifest.xml中声明
    • 应用未启动时也能接收广播
    • 应用被杀死后仍能接收广播
    • Android 8.0后对隐式广播有限制
    • 生命周期与应用生命周期无关
  2. 动态注册

    • 在代码中通过registerReceiver()方法注册
    • 只有在应用运行时才能接收广播
    • 必须在组件销毁前调用unregisterReceiver()注销
    • 生命周期与注册的组件生命周期相关
    • 可以接收所有类型的广播

问题2:标准广播和有序广播有什么区别?

答案

  1. 标准广播(Normal Broadcast)

    • 完全异步执行
    • 所有接收器几乎同时接收到广播
    • 效率高
    • 接收器之间互不干扰
    • 无法被拦截
    • 通过sendBroadcast()方法发送
  2. 有序广播(Ordered Broadcast)

    • 同步执行
    • 按照接收器优先级顺序传递
    • 优先级通过intent-filter的android:priority属性设置
    • 前面的接收器可以修改广播内容
    • 可以被拦截(abortBroadcast())
    • 通过sendOrderedBroadcast()方法发送

问题3:如何在BroadcastReceiver中执行耗时操作?

答案
BroadcastReceiver的onReceive()方法在主线程中执行,不应该执行耗时操作。处理耗时任务的方法有:

  1. 启动Service:在onReceive()中启动Service处理耗时任务

    Intent serviceIntent = new Intent(context, MyService.class);
    context.startService(serviceIntent);
    
  2. 使用WorkManager:调度后台任务

    OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(MyWorker.class).build();
    WorkManager.getInstance(context).enqueue(workRequest);
    
  3. 使用goAsync():获取PendingResult延长生命周期

    @Override
    public void onReceive(Context context, Intent intent) {final PendingResult pendingResult = goAsync();new Thread(() -> {// 执行耗时操作// ...pendingResult.finish();}).start();
    }
    

问题4:Android 8.0对广播接收器有哪些限制?如何适配?

答案
Android 8.0(API 26)对广播接收器的主要限制:

  1. 隐式广播限制:大多数隐式广播(没有明确指定接收器的广播)无法通过静态注册的方式接收

  2. 例外情况

    • 面向特定应用的显式广播
    • 特定系统广播(如BOOT_COMPLETED、ACTION_LOCALE_CHANGED等)
  3. 适配方法

    • 使用动态注册替代静态注册
    • 使用JobScheduler或WorkManager替代部分广播场景
    • 对于自定义广播,使用显式Intent指定接收器
    • 使用Context.sendBroadcast(Intent, String)方法发送带权限的广播

6.2 实际开发中的广播问题

问题1:如何防止应用外的广播干扰应用内的广播?

答案

  1. 使用LocalBroadcastManager(已废弃但仍可用)
  2. 使用自定义权限
    <!-- 在AndroidManifest.xml中定义权限 -->
    <permission android:name="com.example.MY_PERMISSION" android:protectionLevel="signature" /><!-- 在接收器中使用权限 -->
    <receiver android:name=".MyReceiver" android:permission="com.example.MY_PERMISSION" />
    
  3. 使用显式Intent:明确指定接收器组件
  4. 使用其他通信机制:如LiveData、EventBus等

问题2:如何在应用被杀死后仍能接收广播?

答案

  1. 使用静态注册:在AndroidManifest.xml中注册接收器
  2. 处理系统限制
    • 针对Android 8.0+,只能接收特定系统广播
    • 可能需要申请自启动权限(不同厂商有不同策略)
  3. 替代方案
    • 使用FCM(Firebase Cloud Messaging)
    • 使用WorkManager的周期性任务
    • 使用前台服务保持应用活跃

七、开源项目实战分析

7.1 分析EventBus中的广播机制

EventBus是一个流行的事件总线库,它的实现原理与BroadcastReceiver类似,但更加轻量和高效:

// EventBus简化实现
public class SimpleEventBus {private Map<Class<?>, List<Subscription>> subscriptionsByEventType = new HashMap<>();// 注册订阅者public void register(Object subscriber) {Class<?> subscriberClass = subscriber.getClass();// 通过反射找到所有带@Subscribe注解的方法List<SubscriberMethod> methods = findSubscriberMethods(subscriberClass);for (SubscriberMethod method : methods) {subscribe(subscriber, method);}}// 添加订阅private void subscribe(Object subscriber, SubscriberMethod method) {Class<?> eventType = method.eventType;Subscription subscription = new Subscription(subscriber, method);List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);if (subscriptions == null) {subscriptions = new ArrayList<>();subscriptionsByEventType.put(eventType, subscriptions);}subscriptions.add(subscription);}// 发布事件(类似于发送广播)public void post(Object event) {Class<?> eventClass = event.getClass();List<Subscription> subscriptions = subscriptionsByEventType.get(eventClass);if (subscriptions != null) {for (Subscription subscription : subscriptions) {postToSubscriber(subscription, event);}}}// 向订阅者发送事件private void postToSubscriber(Subscription subscription, Object event) {try {subscription.method.method.invoke(subscription.subscriber, event);} catch (Exception e) {e.printStackTrace();}}// 注销订阅者public void unregister(Object subscriber) {// 从所有事件类型的订阅列表中移除该订阅者for (List<Subscription> subscriptions : subscriptionsByEventType.values()) {Iterator<Subscription> iterator = subscriptions.iterator();while (iterator.hasNext()) {if (iterator.next().subscriber == subscriber) {iterator.remove();}}}}// 订阅信息类private static class Subscription {final Object subscriber;final SubscriberMethod method;Subscription(Object subscriber, SubscriberMethod method) {this.subscriber = subscriber;this.method = method;}}// 订阅方法类private static class SubscriberMethod {final Method method;final Class<?> eventType;SubscriberMethod(Method method, Class<?> eventType) {this.method = method;this.eventType = eventType;}}
}

与BroadcastReceiver相比,EventBus有以下特点:

  1. 完全在应用内部使用,不涉及系统广播
  2. 基于反射实现,不需要显式注册IntentFilter
  3. 支持更细粒度的事件类型(基于类型而非Action字符串)
  4. 性能更高,没有系统开销

7.2 分析RxJava中的事件处理机制

RxJava也可以用于替代BroadcastReceiver实现应用内通信:

// 创建事件总线
public class RxBus {private static final RxBus INSTANCE = new RxBus();private final Subject<Object> bus = PublishSubject.create().toSerialized();private RxBus() {// 私有构造函数}public static RxBus getInstance() {return INSTANCE;}// 发送事件public void post(Object event) {bus.onNext(event);}// 订阅事件public <T> Observable<T> toObservable(Class<T> eventType) {return bus.ofType(eventType);}
}// 使用示例
public class MainActivity extends AppCompatActivity {private Disposable subscription;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 订阅事件subscription = RxBus.getInstance().toObservable(MessageEvent.class).observeOn(AndroidSchedulers.mainThread()).subscribe(event -> {// 处理接收到的事件Toast.makeText(this, event.getMessage(), Toast.LENGTH_SHORT).show();});// 发送事件按钮findViewById(R.id.btn_send).setOnClickListener(v -> {RxBus.getInstance().post(new MessageEvent("Hello RxBus!"));});}@Overrideprotected void onDestroy() {super.onDestroy();// 取消订阅if (subscription != null && !subscription.isDisposed()) {subscription.dispose();}}// 事件类public static class MessageEvent {private String message;public MessageEvent(String message) {this.message = message;}public String getMessage() {return message;}}
}

八、总结

BroadcastReceiver是Android中用于接收广播消息的重要组件,它提供了一种松耦合的通信机制,使应用能够响应系统事件或其他应用发出的广播。

在实际开发中,我们需要根据不同场景选择合适的广播接收方式:

  1. 系统广播:使用动态注册方式,在应用运行期间接收系统事件
  2. 应用内通信:考虑使用LiveData、EventBus等替代方案,性能更好
  3. 跨应用通信:使用显式广播并添加权限控制,确保安全性

随着Android版本的更新,广播接收器的使用受到了越来越多的限制,特别是在Android 8.0及以上版本。开发者需要了解这些限制并采取适当的适配措施,如使用动态注册替代静态注册,或使用其他组件(如JobScheduler、WorkManager)替代部分广播场景。

总的来说,BroadcastReceiver是Android系统中不可或缺的组件,合理使用它可以帮助我们构建响应性更强、交互更灵活的应用程序。


文章转载自:

http://cmvFW8EC.bxgpy.cn
http://znUJOPOl.bxgpy.cn
http://J7ibhXGn.bxgpy.cn
http://ju9iDLZN.bxgpy.cn
http://bEMzlewb.bxgpy.cn
http://IIThcFC7.bxgpy.cn
http://Hj1XVMDE.bxgpy.cn
http://9DDA2OPV.bxgpy.cn
http://MwOZEwX5.bxgpy.cn
http://FkYg0dN3.bxgpy.cn
http://rYJhz0YN.bxgpy.cn
http://kxK1AUws.bxgpy.cn
http://l8MpgHoP.bxgpy.cn
http://NAgHmvjW.bxgpy.cn
http://GnCqIlzd.bxgpy.cn
http://GHVau3pz.bxgpy.cn
http://Xbm4hhyl.bxgpy.cn
http://Q9XmcXoN.bxgpy.cn
http://ZScCaPbj.bxgpy.cn
http://7eyJx24A.bxgpy.cn
http://r9SxS0IA.bxgpy.cn
http://doVD5LLg.bxgpy.cn
http://qyA6p6VG.bxgpy.cn
http://I61kKAfg.bxgpy.cn
http://dgCT5VUg.bxgpy.cn
http://ja2WQtmp.bxgpy.cn
http://FKgDJi3w.bxgpy.cn
http://yORIPVKt.bxgpy.cn
http://sdBaq4CA.bxgpy.cn
http://igGSMY8t.bxgpy.cn
http://www.dtcms.com/wzjs/768633.html

相关文章:

  • xsl做书店网站国美的网站做的怎么样
  • php 企业网站开发实例什么叫网站收录提交
  • 微信开发网站开发未来前景盐城网站开发公司电话
  • 昆明 网站 制作网络广告设计课程
  • 违规网站开发 开发者如何规避风险英文seo公司
  • 网站设计集团腾讯广告投放平台官网
  • 无锡网站制作启航建立企业网站价格
  • 怎么看国外设计网站西安网站seo诊断
  • 可以看设计的网站有哪些网站建设教学廊坊
  • 上海信息技术做网站网页美工软件
  • 网站首页 如何设置网址短链接在线生成免费
  • 重庆营销网站建设提高网站排名
  • 农业服务网站建设方案网站建设动态页面修改删除
  • 济南网站建设外包公司哪家好施工企业如何节约人力成本
  • 阿里指数官方网站微信小程序云开发收费标准
  • 企业名录网站 优帮云免费空间凡科
  • 服装商城网站建设方案做网站大图片
  • 天津网站优化哪家好连云港关键字优化预订
  • 电子商务网站设计原则重庆市招标投标综合网
  • 鲜花网站建设方案网站规划与建设课程
  • 数字资产交易网站开发wordpress媒体库现实不全
  • 电子商务网站开发 微盘下载常州网站建设要多少钱
  • 喀什住房和城乡建设局网站如何做国际网站首页
  • 邢台移动网站建设公司天桥网站建设
  • 启动门户网站建设传奇一条龙
  • 哪个公司的网站做得好河南省建筑劳务信息网
  • 企业为什么做网站系统长沙麓谷网站建设
  • c2c网站的特点及主要功能软文投稿平台有哪些
  • 如何布置网站想自己在家做外贸网站
  • 网站设计建设合同网站定制建设公司