Android 音乐APP(五)音乐通知栏、后台播放音乐

简介: Android 音乐APP(五)音乐通知栏、后台播放音乐

Android 音乐通知栏


前言


 这篇文章的标题有些言简意赅了,也突出了这篇文章的核心,那就是通知栏的操作,你可以看到市面上的音乐类APP都会有这个操作,通过音乐通知栏可以播放暂停、上一曲、下一曲、收藏、显示歌词等等。当然我这个Demo目前不考虑这么多,先实现播放暂停、上一曲、下一曲这些基本功能再说,你说对吧。


正文


  在第四篇文章的到最后显示了通知栏,那么为什么我要把通知的的操作单独放到一篇文章来进行讲解呢?因为里面有很多业务逻辑,还有通信的关系,所以才这么做的。


① 通知栏按钮点击监听


  要实现具体的业务功能,首先要监听到点击事件,这一点是毋庸置疑的,谁赞成,谁反对。首先增加几个全局变量,打开Constant


  /**
     * 歌曲播放
     */
    public static final String PLAY = "play";
    /**
     * 歌曲暂停
     */
    public static final String PAUSE = "pause";
    /**
     * 上一曲
     */
    public static final String PREV = "prev";
    /**
     * 下一曲
     */
    public static final String NEXT = "next";
    /**
     * 关闭通知栏
     */
    public static final String CLOSE = "close";
    /**
     * 进度变化
     */
    public static final String PROGRESS = "progress";


这些都是用来表明当前歌曲的状态的,至关重要。之前我通过RemoteViews来指定一个布局文件,从而实现自定义通知栏样式的效果,那么对于通知栏页面的按钮的点击事件,也是交给RemoteViews来完成来的,下面进行实例化,把它变成成员变量。


在Service中实例化

private static RemoteViews remoteViews;


然后单独写一个方法对RemoteViews进行初始化配置。


  /**
     * 初始化自定义通知栏 的按钮点击事件
     */
    private void initRemoteViews() {
        remoteViews = new RemoteViews(this.getPackageName(), R.layout.notification);
        //通知栏控制器上一首按钮广播操作
        Intent intentPrev = new Intent(PREV);
        PendingIntent prevPendingIntent = PendingIntent.getBroadcast(this, 0, intentPrev, 0);
        //为prev控件注册事件
        remoteViews.setOnClickPendingIntent(R.id.btn_notification_previous, prevPendingIntent);
        //通知栏控制器播放暂停按钮广播操作  //用于接收广播时过滤意图信息
        Intent intentPlay = new Intent(PLAY);
        PendingIntent playPendingIntent = PendingIntent.getBroadcast(this, 0, intentPlay, 0);
        //为play控件注册事件
        remoteViews.setOnClickPendingIntent(R.id.btn_notification_play, playPendingIntent);
        //通知栏控制器下一首按钮广播操作
        Intent intentNext = new Intent(NEXT);
        PendingIntent nextPendingIntent = PendingIntent.getBroadcast(this, 0, intentNext, 0);
        //为next控件注册事件
        remoteViews.setOnClickPendingIntent(R.id.btn_notification_next, nextPendingIntent);
        //通知栏控制器关闭按钮广播操作
        Intent intentClose = new Intent(CLOSE);
        PendingIntent closePendingIntent = PendingIntent.getBroadcast(this, 0, intentClose, 0);
        //为close控件注册事件
        remoteViews.setOnClickPendingIntent(R.id.btn_notification_close, closePendingIntent);
    }


目前通知栏上看到的按钮只有四个,因为播放和暂停是一个按钮,到时候可以根据MediaPlayer的播放状态做进一步的处理,上面四个按钮,点击之后会发送一个广播,既然有广播,那自然要有一个广播接收器,就好比,你到淘宝上买衣服,别人给你发货了,你总要设置一个收货地址吧。这是一个道理的。至于广播接收器,可以写在Service里面,作为一个内部类使用。那么先创建这个内部类。


  /**
     * 广播接收器 (内部类)
     */
    public class MusicReceiver extends BroadcastReceiver {
        public static final String TAG = "MusicReceiver";
        @Override
        public void onReceive(Context context, Intent intent) {
          //UI控制
            UIControl(intent.getAction(), TAG);
        }
    }


然后来看看UIControl方法。


  /**
     * 页面的UI 控制 ,通过服务来控制页面和通知栏的UI
     *
     * @param state 状态码
     * @param tag
     */
    private void UIControl(String state, String tag) {
        switch (state) {
            case PLAY:
                BLog.d(tag,PLAY+" or "+PAUSE);
                break;
            case PREV:
                BLog.d(tag,PREV);
                break;
            case NEXT:
                BLog.d(tag,NEXT);
                break;
            case CLOSE:
                BLog.d(tag,CLOSE);
                break;
            default:
                break;
        }
    }


对应四个通知栏的按钮,这是是作为广播的接收。但是要实际收到,还要注册才行。


所以要注册动态广播。

  /**
     * 注册动态广播
     */
    private void registerMusicReceiver() {
        musicReceiver = new MusicReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(PLAY);
        intentFilter.addAction(PREV);
        intentFilter.addAction(NEXT);
        intentFilter.addAction(CLOSE);
        registerReceiver(musicReceiver, intentFilter);
    }


在这里你可以发现,我对四个值进行了拦截过滤,也就是说当我点击通知栏的上一曲按钮时,会发送动作名为PREV的广播,而这个时候MusicReceiver拦截到PREV的广播,传递给onReceive。然后在onReceive对不同的动作做不同的处理,目前我只是打印了日志而已。


现在你可以将showNotification方法中的如下代码删除掉。


RemoteViews remoteViews = new RemoteViews(this.getPackageName(), R.layout.notification);

然后在Service中的onCreate中调用。

  @Override
    public void onCreate() {
        super.onCreate();
        initRemoteViews();
        //注册动态广播
        registerMusicReceiver();
    showNotification();
        BLog.d(TAG, "onCreate");
    }


initRemoteViews 方法一定要在 showNotification之前调用,否则你就等着null Object 然后APP崩溃吧。


在服务销毁的时候要解绑广播接收者


  @Override
    public void onDestroy() {
        super.onDestroy();
        if (musicReceiver != null) {
            //解除动态注册的广播
            unregisterReceiver(musicReceiver);
        }
    }


下面运行一下,日志如下:


20201106112907959.png


现在通知栏的按钮点击事件就已经监听到了,下面做通知栏的点击事件。

② 通知栏点击监听


 只要是通知栏按钮以外的点击都属于通知栏的点击,这个要区分开,别搞混了。在写代码要想清楚一点,当我们点击通知栏的时候,要进入那个页面,我仔细观察过其他音乐APP的这个点击通知栏的效果,是从那个页面切换到后台,下次点击通知栏时就进入到那个页面,也就是说它点击跳转的页面是动态的,所以不能是写死的。有了这个业务需求那么就可以开始写代码了。这里也是需要用到广播的,只不过不再是写内部类了。在com.llw.goodmusic下面新建一个receiver的包,然后创建NotificationClickReceiver,里面的两个可以不用勾选。


20201106145045664.png


创建好之后,打开AndroidManifest.xml你会看到如下代码:

<receiver android:name=".receiver.NotificationClickReceiver"/>

下面进入MusicService中,

    //点击整个通知时发送广播
        Intent intent = new Intent(getApplicationContext(), NotificationClickReceiver.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0,
                intent, PendingIntent.FLAG_UPDATE_CURRENT);


然后通过.setContentIntent(pendingIntent)设置进去,如下图所示

20201106145439469.png


下面进入到NotificationClickReceiver中。

package com.llw.goodmusic.receiver;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.llw.goodmusic.utils.BLog;
/**
 * 通知点击广播接收器  跳转到栈顶的Activity ,而不是new 一个新的Activity
 *
 * @author llw
 */
public class NotificationClickReceiver extends BroadcastReceiver {
    public static final String TAG = "NotificationClickReceiver";
    @Override
    public void onReceive(Context context, Intent intent) {
        BLog.d(TAG,"通知栏点击");
    }
}


然后运行,运行之后点击通知栏,再看日志打印,如下所示:


20201106150024610.png


③ 通知栏业务处理


 在上面已经实现了通知栏的点击监听了,下面就要开始进行业务逻辑的处理了。先解决通知栏的点击业务处理,再解决通知栏按钮的点击处理,打开AndroidManager,注意这是之前我自己写的,不是系统的。在里面增加


  /**
     * 弱引用
     */
    private static WeakReference<Activity> activityWeakReference;
    private static Object activityUpdateLock = new Object();
  /**
     * 得到当前Activity
     * @return
     */
    public static Activity getCurrentActivity() {
        Activity currentActivity = null;
        synchronized (activityUpdateLock){
            if (activityWeakReference != null) {
                currentActivity = activityWeakReference.get();
            }
        }
        return currentActivity;
    }
    /**
     * 设置当前Activity
     * @return
     */
    public static void setCurrentActivity(Activity activity) {
        synchronized (activityUpdateLock){
            activityWeakReference = new WeakReference<Activity>(activity);
        }
    }


然后进入到BasicApplication中,在onCreate中写入:

registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
            }
            @Override
            public void onActivityStarted(Activity activity) {
            }
            @Override
            public void onActivityResumed(Activity activity) {
                ActivityManager.setCurrentActivity(activity);
            }
            @Override
            public void onActivityPaused(Activity activity) {
            }
            @Override
            public void onActivityStopped(Activity activity) {
            }
            @Override
            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
            }
            @Override
            public void onActivityDestroyed(Activity activity) {
            }
        });


通过上面得代码就可以得到栈顶的Activity,那么怎么来使用这个Activity呢,进入到NotificationClickReceiver


  @Override
    public void onReceive(Context context, Intent intent) {
        BLog.d(TAG,"通知栏点击");
        //获取栈顶的Activity
        Activity currentActivity = ActivityManager.getCurrentActivity();
        intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        intent.setClass(context, currentActivity.getClass());
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
        context.startActivity(intent);
    }


这样就可以实现,点击通知栏时跳转到栈顶的Activity而不是新建一个Activity。

下面就是针对通知栏的信息显示做处理了,首先肯定要根据不同的音乐显示不同的歌曲信息,这一点毋庸置疑。那么这样的话就不能一开始就显示通知栏了,而是在点击播放按钮的时候显示通知栏,当切歌,或者暂停时更新这个通知栏的状态,于是就可以在MusicService中写入一个这样的方法。


  /**
     * 初始化通知
     */
    private void initNotification() {
        String channelId = "play_control";
        String channelName = "播放控制";
        int importance = NotificationManager.IMPORTANCE_HIGH;
        createNotificationChannel(channelId, channelName, importance);
        //点击整个通知时发送广播
        Intent intent = new Intent(getApplicationContext(), NotificationClickReceiver.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0,
                intent, PendingIntent.FLAG_UPDATE_CURRENT);
        //初始化通知
        notification = new NotificationCompat.Builder(this, "play_control")
                .setContentIntent(pendingIntent)
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.mipmap.icon_big_logo)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.icon_big_logo))
                .setCustomContentView(remoteViews)
                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
                .setAutoCancel(false)
                .setOnlyAlertOnce(true)
                .setOngoing(true)
                .build();
    }


这里就是把原来的showNotification方法改了一下,把显示通知的代码放到改变通知栏状态的时候使用。当然还是要在onCreate中调用这个方法的。

下面先在MusiceService中定义这些变量

  /**
     * 歌曲间隔时间
     */
    private static final int INTERNAL_TIME = 1000;
    /**
     * 歌曲列表
     */
    private static List<Song> mList = new ArrayList<>();
    /**
     * 音乐播放器
     */
    public MediaPlayer mediaPlayer;
    /**
     * 记录播放的位置
     */
    int playPosition = 0;
    /**
     * 通知
     */
    private static Notification notification;
    /**
     * 通知栏视图
     */
    private static RemoteViews remoteViews;
    /**
     * 通知ID
     */
    private int NOTIFICATION_ID = 1;
    /**
     * 通知管理器
     */
    private static NotificationManager manager;
    /**
     * 音乐广播接收器
     */
    private MusicReceiver musicReceiver;


然后写入一个更改通知栏样式的方法,每次对音乐进行控制时都会调用。


  /**
     * 更改通知的信息和UI
     * @param position 歌曲位置
     */
    public void updateNotificationShow(int position) {
        //播放状态判断
        if (mediaPlayer.isPlaying()) {
            remoteViews.setImageViewResource(R.id.btn_notification_play, R.drawable.pause_black);
        } else {
            remoteViews.setImageViewResource(R.id.btn_notification_play, R.drawable.play_black);
        }
        //封面专辑
        remoteViews.setImageViewBitmap(R.id.iv_album_cover, MusicUtils.getAlbumPicture(this, mList.get(position).getPath(), 0));
        //歌曲名
        remoteViews.setTextViewText(R.id.tv_notification_song_name, mList.get(position).getSong());
        //歌手名
        remoteViews.setTextViewText(R.id.tv_notification_singer, mList.get(position).getSinger());
        //发送通知
        manager.notify(NOTIFICATION_ID, notification);
    }


在这个方法里面我调用MusicUtils工具类的getAlbumPicture方法。这个方法我做了一点点改动


改动如下图所示:

20201106170039630.png


下面就是点击播放时的音乐方法了。

  /**
     * 播放
     */
    public void play(int position) {
        if (mediaPlayer == null) {
            mediaPlayer = new MediaPlayer();
            //监听音乐播放完毕事件,自动下一曲
            mediaPlayer.setOnCompletionListener(this);
        }
        //播放时 获取当前歌曲列表是否有歌曲
    mList = LitePal.findAll(Song.class);
        if (mList.size() <= 0) {
            return;
        }
        try {
            //切歌前先重置,释放掉之前的资源
            mediaPlayer.reset();
            playPosition = position;
            //设置播放音频的资源路径
            mediaPlayer.setDataSource(mList.get(position).path);
            mediaPlayer.prepare();
            mediaPlayer.start();
            //显示通知
            updateNotificationShow(position);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


在上面的播放方法中,首先初始化了MediaPlayer,然后添加了播放完成的监听,这个在后面也是要实现的。然后获取当前的播放位置赋值给成员变量,之后通过位置得到歌曲的路径,通过路径来播放音乐,播放音乐之后将位置传递给显示通知栏的方法,此时通知栏的信息久会更改。


在onCreate方法中添加如下代码,获取本地歌曲数据。


mList = LitePal.findAll(Song.class);

这样做是避免空对象导致APP的崩溃。


接下来就是上一曲的方法


  /**
     * 上一首
     */
    public void previousMusic() {
        if (playPosition <= 0) {
            playPosition = mList.size() - 1;
        } else {
            playPosition -= 1;
        }
        play(playPosition);
    }


通过播放位置,先判断当前是为第一首歌,是则将播放位置移动到最后一首,不是则直接减一,之后则调用play方法播放上一首歌曲。


下一曲的方法

  /**
     * 下一首
     */
    public void nextMusic() {
        if (playPosition >= mList.size() - 1) {
            playPosition = 0;
        } else {
            playPosition += 1;
        }
        play(playPosition);
    }


先判断当前是否为最后一首,是的话则从移动到第一首,不是则加一到下一首。然后调用play方法播放下一首歌曲。


暂停继续音乐


  /**
     * 暂停/继续 音乐
     */
    public void pauseOrContinueMusic() {
        if (mediaPlayer.isPlaying()) {
            mediaPlayer.pause();
        } else {
            mediaPlayer.start();
        }
        //更改通知栏播放状态
        updateNotificationShow(playPosition);
    }


更改播放状态


最后是关闭通知栏的方法

  /**
     * 关闭音乐通知栏
     */
    public void closeNotification() {
        if (mediaPlayer != null) {
            if (mediaPlayer.isPlaying()) {
                mediaPlayer.pause();
            }
        }
        manager.cancel(NOTIFICATION_ID);
    }


下面就是调用的地方了


2020110616475015.png


然后还要实现MediaPlayer的音乐播放完成的监听,

public class MusicService extends Service implements MediaPlayer.OnCompletionListener


然后重写onCompletion方法,在里面直接调用nextMusic播放下一曲即可。


  /**
     * 当前音乐播放完成监听
     *
     * @param mp
     */
    @Override
    public void onCompletion(MediaPlayer mp) {
        //下一曲
        nextMusic();
    }


下面就要设置通知出现的入口,一般来说是在点击播放按钮,当前有音乐播放时,才会显示通知。然后在layout下面新建一个通用的底部通知布局。

play_control_layout.xml


<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <!--底部播放控制布局-->
    <LinearLayout
        android:id="@+id/lay_bottom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:background="@color/bottom_bg_color"
        android:gravity="center_vertical"
        android:paddingLeft="@dimen/dp_8"
        android:paddingTop="@dimen/dp_8"
        android:paddingRight="@dimen/dp_16"
        android:paddingBottom="@dimen/dp_8">
        <!-- logo和播放进度 使用相对布局达成覆盖的效果-->
        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
            <!--logo-->
            <com.google.android.material.imageview.ShapeableImageView
                android:id="@+id/iv_logo"
                android:layout_width="@dimen/dp_48"
                android:layout_height="@dimen/dp_48"
                android:padding="1dp"
                android:src="@mipmap/icon_music"
                app:shapeAppearanceOverlay="@style/circleImageStyle"
                app:strokeColor="@color/white"
                app:strokeWidth="@dimen/dp_2" />
            <!--播放进度  自定义View-->
            <com.llw.goodmusic.view.MusicRoundProgressView
                android:id="@+id/music_progress"
                android:layout_width="@dimen/dp_48"
                android:layout_height="@dimen/dp_48"
                app:radius="22dp"
                app:strokeColor="@color/gold_color"
                app:strokeWidth="2dp" />
        </RelativeLayout>
        <!--歌曲信息  歌名 - 歌手 -->
        <com.google.android.material.textview.MaterialTextView
            android:id="@+id/tv_song_name"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:ellipsize="marquee"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:marqueeRepeatLimit="marquee_forever"
            android:paddingLeft="@dimen/dp_12"
            android:paddingRight="@dimen/dp_12"
            android:singleLine="true"
            android:text="Good Music"
            android:textColor="@color/white"
            android:textSize="@dimen/sp_16" />
        <!--歌曲控制按钮-->
        <com.google.android.material.button.MaterialButton
            android:id="@+id/btn_play"
            android:layout_width="@dimen/dp_36"
            android:layout_height="@dimen/dp_36"
            android:insetLeft="@dimen/dp_0"
            android:insetTop="@dimen/dp_0"
            android:insetRight="@dimen/dp_0"
            android:insetBottom="@dimen/dp_0"
            android:theme="@style/Theme.MaterialComponents.Light.NoActionBar"
            app:backgroundTint="@color/transparent"
            app:cornerRadius="@dimen/dp_18"
            app:icon="@mipmap/icon_play"
            app:iconGravity="textStart"
            app:iconPadding="@dimen/dp_0"
            app:iconSize="@dimen/dp_36" />
    </LinearLayout>
</layout>


其实就是之前LocalMusicActivity的底部布局。

20201106165648599.png


下面进入MainActivity中,


  /**
     * 底部logo图标,点击之后弹出当前播放歌曲详情页
     */
    private ShapeableImageView ivLogo;
    /**
     * 底部当前播放歌名
     */
    private MaterialTextView tvSongName;
    /**
     * 底部当前歌曲控制按钮, 播放和暂停
     */
    private MaterialButton btnPlay;
    /**
     * 自定义进度条
     */
    private MusicRoundProgressView musicProgress;
    /**
     * 列表位置
     */
    private int listPosition = 0;


然后在initData中,通过引入的布局绑定控件,并且添加点击监听,下面就可以在

20201106170705430.png


  @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.lay_local_music:
                //本地音乐
                startActivity(new Intent(context, LocalMusicActivity.class));
                break;
            case R.id.btn_play:
                if (mList.size() == 0) {
                    show("没有可播放的音乐,请到 “本地音乐” 进行扫描");
                    return;
                }
                musicService.play(listPosition);
                break;
            default:
                break;
        }
    }


下面运行测试一波:


④ 运行效果图


20201106172042502.gif


结语


  现在已经搞定了后台播放和通知栏控制音乐,下一篇就该是通知栏和Activity的双向控制了。


相关文章
|
2月前
|
XML Java 数据库
安卓项目:app注册/登录界面设计
本文介绍了如何设计一个Android应用的注册/登录界面,包括布局文件的创建、登录和注册逻辑的实现,以及运行效果的展示。
196 0
安卓项目:app注册/登录界面设计
|
3月前
|
存储 开发工具 Android开发
使用.NET MAUI开发第一个安卓APP
【9月更文挑战第24天】使用.NET MAUI开发首个安卓APP需完成以下步骤:首先,安装Visual Studio 2022并勾选“.NET Multi-platform App UI development”工作负载;接着,安装Android SDK。然后,创建新项目时选择“.NET Multi-platform App (MAUI)”模板,并仅针对Android平台进行配置。了解项目结构,包括`.csproj`配置文件、`Properties`配置文件夹、平台特定代码及共享代码等。
271 2
|
3月前
|
XML Android开发 数据格式
🌐Android国际化与本地化全攻略!让你的App走遍全球无障碍!🌍
在全球化背景下,实现Android应用的国际化与本地化至关重要。本文以一款旅游指南App为例,详细介绍如何通过资源文件拆分与命名、适配布局与方向、处理日期时间及货币格式、考虑文化习俗等步骤,完成多语言支持和本地化调整。通过邀请用户测试并收集反馈,确保应用能无缝融入不同市场,提升用户体验与满意度。
123 3
|
2月前
|
安全 网络安全 Android开发
深度解析:利用Universal Links与Android App Links实现无缝网页至应用跳转的安全考量
【10月更文挑战第2天】在移动互联网时代,用户经常需要从网页无缝跳转到移动应用中。这种跳转不仅需要提供流畅的用户体验,还要确保安全性。本文将深入探讨如何利用Universal Links(仅限于iOS)和Android App Links技术实现这一目标,并分析其安全性。
374 0
|
3月前
|
XML 数据库 Android开发
10分钟手把手教你用Android手撸一个简易的个人记账App
该文章提供了使用Android Studio从零开始创建一个简单的个人记账应用的详细步骤,包括项目搭建、界面设计、数据库处理及各功能模块的实现方法。
|
29天前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
16天前
|
搜索推荐 前端开发 API
探索安卓开发中的自定义视图:打造个性化用户界面
在安卓应用开发的广阔天地中,自定义视图是一块神奇的画布,让开发者能够突破标准控件的限制,绘制出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战技巧,逐步揭示如何在安卓平台上创建和运用自定义视图来提升用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你的应用在众多同质化产品中脱颖而出。
40 19
|
29天前
|
IDE Java 开发工具
移动应用与系统:探索Android开发之旅
在这篇文章中,我们将深入探讨Android开发的各个方面,从基础知识到高级技术。我们将通过代码示例和案例分析,帮助读者更好地理解和掌握Android开发。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和技巧。让我们一起开启Android开发的旅程吧!
|
16天前
|
JSON Java API
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
41 14
|
19天前
|
Java Linux 数据库
探索安卓开发:打造你的第一款应用
在数字时代的浪潮中,每个人都有机会成为创意的实现者。本文将带你走进安卓开发的奇妙世界,通过浅显易懂的语言和实际代码示例,引导你从零开始构建自己的第一款安卓应用。无论你是编程新手还是希望拓展技术的开发者,这篇文章都将为你打开一扇门,让你的创意和技术一起飞扬。
下一篇
DataWorks