扣丁学堂(六)——音乐播放独立页面的实现

本文出自:http://blog.csdn.net/dt235201314/article/details/51360013

一丶音乐播放页实现功能

1.音乐格信息显示,大图显示

2.播放功能,上一曲,下一曲,暂停

3.音乐进度显示

4.切换播放模式

二丶显示效果

三丶原理及代码实现

1.自定义接口回调的方法实现UI状态切换(进度位置,播放那一首歌)

2.seekbar实现歌曲进度同步及监听

3.service统一实现Activity,Fragment的播放功能及UI图片统一

4.BaseActivity基类统一实现服务绑定,音乐播放状态,直接调用MusicPlayService

代码实现

activity_play_ui.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/skin2">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/relativeLayout">

        <ImageView
            android:layout_centerVertical="true"
            android:id="@+id/iv_pull_down"
            android:layout_width="wrap_content"
            android:layout_height="20dp"
            android:src="@drawable/backtrack"
            android:layout_marginLeft="10dp"/>

        <LinearLayout
            android:id="@+id/ll_play_ui_top"
            android:gravity="center"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:layout_marginTop="5dp"
            android:layout_toRightOf="@+id/iv_pull_down"
            android:layout_toLeftOf="@+id/iv_share">

            <TextView
                android:id="@+id/tv_play_ui_song"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="听妈妈的话"
                android:textColor="@color/white"
                android:textSize="18sp"/>

            <TextView
                android:id="@+id/tv_play_ui_artist"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="#c1c1c1"
                android:paddingTop="5dp"
                android:text="周杰伦"/>

        </LinearLayout>

        <ImageView
            android:id="@+id/iv_share"
            android:layout_width="wrap_content"
            android:layout_height="25dp"
            android:src="@drawable/share"
            android:layout_marginRight="10dp"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"/>
    </RelativeLayout>

    <LinearLayout
        android:layout_alignParentBottom="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:id="@+id/linearLayout">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <TextView
                android:id="@+id/tv_play_ui_play_time"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="00:00"
                android:layout_centerVertical="true"
                android:layout_marginLeft="10dp"
                android:textColor="@color/white"/>

            <SeekBar
                android:id="@+id/sb_play_ui_seekbar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:thumb="@drawable/seekbar_cycle"
                android:layout_toRightOf="@+id/tv_play_ui_play_time"
                android:layout_toLeftOf="@+id/tv_play_ui_end_time"/>

            <TextView
                android:id="@+id/tv_play_ui_end_time"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="00:00"
                android:layout_centerVertical="true"
                android:textColor="@color/white"
                android:layout_marginRight="10dp"
                android:layout_alignParentRight="true"/>
        </RelativeLayout>

        <LinearLayout
            android:gravity="center_vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="30dp"
            android:layout_marginRight="30dp"
            android:layout_marginTop="20dp"
            android:orientation="horizontal">

            <ImageView
                android:id="@+id/iv_play_ui_play_mode"
                android:layout_width="wrap_content"
                android:layout_height="30dp"
                android:src="@drawable/list_cycle"
                android:layout_weight="1"/>

            <ImageView
                android:id="@+id/iv_play_ui_previous"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/previous"
                android:layout_weight="1"/>

            <ImageView
                android:id="@+id/iv_play_ui_play"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/play"
                android:layout_weight="1"/>

            <ImageView
                android:id="@+id/iv_play_ui_next"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/next"
                android:layout_weight="1"/>

            <ImageView
                android:id="@+id/iv_play_ui_menu"
                android:layout_width="wrap_content"
                android:layout_height="35dp"
                android:src="@drawable/menu"
                android:layout_weight="1"/>
        </LinearLayout>

        <LinearLayout
            android:layout_marginLeft="70dp"
            android:layout_marginRight="70dp"
            android:layout_marginTop="20dp"
            android:layout_marginBottom="10dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <ImageView
                android:id="@+id/iv_play_ui_like"
                android:layout_width="wrap_content"
                android:layout_height="25dp"
                android:layout_weight="1"
                android:src="@drawable/like"/>

            <ImageView
                android:id="@+id/iv_play_ui_download"
                android:layout_width="wrap_content"
                android:layout_height="25dp"
                android:layout_weight="1"
                android:src="@drawable/download"/>

            <ImageView
                android:id="@+id/iv_play_ui_add"
                android:layout_width="wrap_content"
                android:layout_height="28dp"
                android:layout_weight="1"
                android:src="@drawable/add"/>

        </LinearLayout>

    </LinearLayout>

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="250dp"
        android:background="#00FFFFFF"
        android:id="@+id/iv_ablum2"
        android:layout_below="@+id/relativeLayout"
        android:layout_marginTop="25dp"
         />

</RelativeLayout>

PlayUIActivity.java

public class PlayUIActivity extends BaseActivity implements View.OnClickListener{

    private ImageView iv_pull_down,iv_play_ui_play,iv_play_ui_next,iv_play_ui_previous,iv_play_ui_play_mode,iv_ablum2;
    private TextView tv_play_ui_song,tv_play_ui_artist,tv_play_ui_end_time,tv_play_ui_play_time;
    private ArrayList<Mp3Info> mp3Infos;
    private SeekBar sb_play_ui_seekbar;
    private static final int UPDATE_TIME = 0x1;
    private static MyHandler myHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_play_ui);
        iv_pull_down = (ImageView)findViewById(R.id.iv_pull_down);
        iv_ablum2 = (ImageView)findViewById(R.id.iv_ablum2);
        tv_play_ui_song = (TextView)findViewById(R.id.tv_play_ui_song);
        tv_play_ui_artist = (TextView)findViewById(R.id.tv_play_ui_artist);
        tv_play_ui_end_time = (TextView)findViewById(R.id.tv_play_ui_end_time);
        tv_play_ui_play_time = (TextView)findViewById(R.id.tv_play_ui_play_time);
        iv_play_ui_play = (ImageView)findViewById(R.id.iv_play_ui_play);
        iv_play_ui_next = (ImageView)findViewById(R.id.iv_play_ui_next);
        iv_play_ui_previous = (ImageView)findViewById(R.id.iv_play_ui_previous);
        iv_play_ui_play_mode = (ImageView)findViewById(R.id.iv_play_ui_play_mode);
        sb_play_ui_seekbar = (SeekBar)findViewById(R.id.sb_play_ui_seekbar);
        iv_pull_down.setOnClickListener(this);
        iv_play_ui_play.setOnClickListener(this);
        iv_play_ui_next.setOnClickListener(this);
        iv_play_ui_previous.setOnClickListener(this);
        iv_play_ui_play_mode.setOnClickListener(this);
        mp3Infos = MediaUtils.getMp3Infos(this);
        myHandler = new MyHandler(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    @Override
    protected void onResume() {
        super.onResume();
        bindMusicPlayService();
    }

    @Override
    protected void onPause() {
        super.onPause();
        unbindMusicPlayService();
    }

    /**
     * 进度条控件已经内部处理过了,开始时间的改变是在子线程中改变主线程的UI,这当然是不可以的
     * 怎么办呢,用你最熟悉的Handler处理吧
     */
    static class MyHandler extends android.os.Handler{
        //内部类去要想使用外部类的权限,就得把外部类拿进来
        private PlayUIActivity playUIActivity;
        public MyHandler(PlayUIActivity playUIActivity){
            this.playUIActivity = playUIActivity;
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if(playUIActivity!=null){
                switch (msg.what){
                    case UPDATE_TIME:
                        playUIActivity.tv_play_ui_play_time.setText(MediaUtils.formatTime(msg.arg1));
                        break;
                }
            }
        }
    }

    //这里是子线程,不断的发送msg给主线程,通知其更改UI
    @Override
    public void publish(int progress) {
        Message msg = myHandler.obtainMessage(UPDATE_TIME);
        msg.arg1 = progress;
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        myHandler.sendMessage(msg);
        sb_play_ui_seekbar.setProgress(progress);
    }

    @Override
    public void change(int position) {
        Mp3Info mp3Info = mp3Infos.get(position);
        tv_play_ui_song.setText(mp3Info.getTitle());
        tv_play_ui_artist.setText(mp3Info.getArtist());
        tv_play_ui_end_time.setText(MediaUtils.formatTime(mp3Info.getDuration()));
        iv_play_ui_play.setImageResource(R.drawable.pause);
        //获取专辑封面图片
        Bitmap albumBitmap = MediaUtils.getArtwork(this, mp3Info.getId(), mp3Info.getAlbumId(), true, false);
        //改变播放界面专辑封面图片
        iv_ablum2.setImageBitmap(albumBitmap);
        sb_play_ui_seekbar.setProgress(0);
        sb_play_ui_seekbar.setMax((int)mp3Info.getDuration());
        if(musicPlayService.isPlaying()){
            iv_play_ui_play.setImageResource(R.drawable.pause);
        }else {
            iv_play_ui_play.setImageResource(R.drawable.play);
        }

        switch (musicPlayService.getPlay_mode()){
            case MusicPlayService.ORDER_PLAY:
                iv_play_ui_play_mode.setImageResource(R.drawable.list_cycle);
                //iv_play_ui_play_mode.setTag(MusicPlayService.ORDER_PLAY);
                break;
            case MusicPlayService.RANDOM_PLAY:
                iv_play_ui_play_mode.setImageResource(R.drawable.random);
                //iv_play_ui_play_mode.setTag(MusicPlayService.RANDOM_PLAY);
                break;
            case MusicPlayService.SINGLE_PLAY:
                iv_play_ui_play_mode.setImageResource(R.drawable.single_cycle);
                //iv_play_ui_play_mode.setTag(MusicPlayService.SINGLE_PLAY);
                break;
            default:
                break;
        }

    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.iv_pull_down:
                finish();
                overridePendingTransition(R.anim.abc_fade_in, R.anim.abc_fade_out);
                break;
            case R.id.iv_play_ui_play:
                if(musicPlayService.isPlaying()){
                    musicPlayService.pause();
                    iv_play_ui_play.setImageResource(R.drawable.play);
                }else{
                    if(musicPlayService.isPause()){
                        musicPlayService.start();
                        iv_play_ui_play.setImageResource(R.drawable.pause);
                    }else{
                        musicPlayService.play(0);
                    }
                }
                break;
            case R.id.iv_play_ui_previous:
                musicPlayService.previous();
                break;
            case R.id.iv_play_ui_next:
                musicPlayService.next();
                break;
            case R.id.iv_play_ui_play_mode:
                switch (musicPlayService.getPlay_mode()){
                    case MusicPlayService.ORDER_PLAY:
                        iv_play_ui_play_mode.setImageResource(R.drawable.random);
                        musicPlayService.setPlay_mode(MusicPlayService.RANDOM_PLAY);
                        break;
                    case MusicPlayService.RANDOM_PLAY:
                        iv_play_ui_play_mode.setImageResource(R.drawable.single_cycle);
                        musicPlayService.setPlay_mode(MusicPlayService.SINGLE_PLAY);
                        break;
                    case MusicPlayService.SINGLE_PLAY:
                        iv_play_ui_play_mode.setImageResource(R.drawable.list_cycle);
                        musicPlayService.setPlay_mode(MusicPlayService.ORDER_PLAY);
                }
                break;
            default:
                break;

        }
    }
}

BaseActivity.java

/**
 * 自定义基础activity,用来让其他activity继承,作为工具activity,用于绑定服务
 */
public abstract class BaseActivity extends FragmentActivity {

    protected MusicPlayService musicPlayService;
    private boolean isBound = false;

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

    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            MusicPlayService.PlayBinder playBinder = (MusicPlayService.PlayBinder)iBinder;
            musicPlayService = playBinder.getMusicPlayService();
            musicPlayService.setMusicUpdateListener(musicUpdateListener);
            //绑定成功后调用监听onChange方法
            musicUpdateListener.onChange(musicPlayService.getCurrentPosition());
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            musicPlayService = null;
            isBound = false;
        }
    };

    private MusicPlayService.MusicUpdateListener musicUpdateListener = new MusicPlayService.MusicUpdateListener(){
        @Override
        public void onPublish(int progress) {
            publish(progress);
        }

        @Override
        public void onChange(int position) {
            change(position);
        }
    };

    public abstract void publish(int progress);
    public abstract void change(int position);

    //绑定服务
    public void bindMusicPlayService(){
        if(!isBound){
            Intent intent = new Intent(this,MusicPlayService.class);
            bindService(intent,conn,BIND_AUTO_CREATE);
            isBound = true;
        }

    }

    //解除绑定服务
    public void unbindMusicPlayService(){
        if(isBound){
            unbindService(conn);
            isBound = false;
        }

    }
}

MusicPlayService.java

/**
 * 实现功能:
 * 1、点击列表上的某首歌播放
 * 2、点击播放按钮,从暂停转为播放状态
 * 3、点击暂停按钮,从播放状态转为暂停状态
 * 4、上一首
 * 5、下一首
 * 6、播放进度显示
 * 7、播放模式
 */
public class  MusicPlayService extends Service implements MediaPlayer.OnCompletionListener,MediaPlayer.OnErrorListener{

    private MediaPlayer mediaPlayer;
    private ArrayList<Mp3Info> mp3Infos;
    private int currentPosition;//列表当前位置
    private MusicUpdateListener musicUpdateListener;//设置属性
    private boolean isPause = false;

    //顺序播放、单曲循环、随机播放
    public static final int ORDER_PLAY = 1;
    public static final int RANDOM_PLAY = 2;
    public static final int SINGLE_PLAY = 3;
    public int play_mode = ORDER_PLAY;

    //用于设置或者获得播放模式
    public int getPlay_mode() {
        return play_mode;
    }

    public void setPlay_mode(int play_mode) {
        this.play_mode = play_mode;
    }

    //在fragment或者activity中轻松获得状态
    public boolean isPause(){
        return isPause;
    }

    //开启线程池
    private ExecutorService es = Executors.newSingleThreadExecutor();

    Runnable updateStatusRunnable = new Runnable() {
        @Override
        public void run() {
            while (true){
                if(musicUpdateListener!=null&&mediaPlayer!=null&&mediaPlayer.isPlaying()){
                    musicUpdateListener.onPublish(getCurrentProgress());
                }
            }
        }
    };

    public MusicPlayService() {

    }

    Random random = new Random();
    //用于监听当前歌曲播放完后,下一首该如何播放
    @Override
    public void onCompletion(MediaPlayer mediaPlayer) {
        switch (play_mode){
            case ORDER_PLAY:
                next();
                break;
            case RANDOM_PLAY:
                play(random.nextInt(mp3Infos.size()));
                break;
            case SINGLE_PLAY:
                play(currentPosition);
                break;
            default:
                break;
        }
    }

    @Override
    public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
        mediaPlayer.reset();
        return false;
    }

    class PlayBinder extends Binder{
        public MusicPlayService getMusicPlayService(){
            return MusicPlayService.this;
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mediaPlayer = new MediaPlayer();
        mp3Infos = MediaUtils.getMp3Infos(this);
        mediaPlayer.setOnCompletionListener(this);
        mediaPlayer.setOnErrorListener(this);
        //在进入每一个绑定service时,就监听进度改变事件,而状态改变监听则是在启动播放的时候
        es.execute(updateStatusRunnable);
    }

    //启动线程就得销毁
    @Override
    public void onDestroy() {
        super.onDestroy();
        if(es!=null && es.isTerminated()){
            es.shutdown();
            es = null;
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new PlayBinder();
    }

    //点击列表上的某首歌播放
    public void play(int position){
        if(position>=0 && position<mp3Infos.size()){
            Mp3Info mp3Info = mp3Infos.get(position);
            try {
                mediaPlayer.reset();
                mediaPlayer.setDataSource(this, Uri.parse(mp3Info.getUrl()));
                mediaPlayer.prepare();
                mediaPlayer.start();
                currentPosition = position;
            }catch (IOException e){
                e.printStackTrace();
            }
            if(musicUpdateListener!=null){
                musicUpdateListener.onChange(currentPosition);
            }
        }
    }

    //点击播放按钮,从暂停转为播放状态
    public void start(){
        if(mediaPlayer!=null && !mediaPlayer.isPlaying()){
            mediaPlayer.start();
        }
    }

    //点击暂停按钮,从播放状态转为暂停状态
    public void pause(){
        if(mediaPlayer.isPlaying()){
            mediaPlayer.pause();
            isPause = true;
        }
    }

    //下一首
    public void next(){
        if(currentPosition >= mp3Infos.size()-1){
            currentPosition = 0;
        }else{
            currentPosition++;
        }
        play(currentPosition);
    }

    //上一首
    public void previous(){
        if(currentPosition<=0){
            currentPosition = mp3Infos.size()-1;
        }else{
            currentPosition--;
        }
        play(currentPosition);
    }

    //更新状态的接口
    public interface MusicUpdateListener{
        public void onPublish(int progress);
        public void onChange(int position);
    }

    public void setMusicUpdateListener(MusicUpdateListener musicUpdateListener) {
        this.musicUpdateListener = musicUpdateListener;
    }

    //在音乐播放中,获得播放的位置信息
    public int getDuration(){
        return mediaPlayer.getDuration();
    }

    //跳转到某个地方
    public void seekTo(int msec){
        mediaPlayer.seekTo(msec);
    }

    //返回当前的位置
    public int getCurrentPosition(){

        return currentPosition;
    }

    //获得当前位置
    public int getCurrentProgress(){
        if(mediaPlayer!=null && mediaPlayer.isPlaying()){
            return mediaPlayer.getCurrentPosition();
        }
        return 0;
    }

    //反馈状态
    public boolean isPlaying(){
        if(mediaPlayer!=null&&mediaPlayer.isPlaying()){
            return mediaPlayer.isPlaying();
        }
        return false;
    }

}
时间: 2024-10-17 07:18:11

扣丁学堂(六)——音乐播放独立页面的实现的相关文章

【扣丁学堂】给自己一个机会、人生才能华丽转身!

每日一课:扣丁学堂 毕业2年没有找到工作,在扣丁学堂学习4个月iOS开发,年薪15万. 我叫曾加,来自北方的坝上草原,08年毕业于张家口建筑学院,计算机系,由于是一个专科学校,加之学校学习的课程离企业开发相差甚远.辗转2年相继在张家口.北京.天津几个城市找工作都没有什么结果-, 直到2015年4月在网上无意中发现了扣丁学堂这个网站,上面专门是讲移动开发的,有iOS.Android和Cocos2d-x游戏开发等课程.课程很系统.很精细.这里提供了免费的视频课程. 因为找了两年工作了也很着急,俗话说

【扣丁学堂】威哥:Android会死,你还学吗?

每日一课:扣丁学堂 标题这个问题笔者被很多童鞋问了N次,不管是QQ里.微信里.微博里.还是更私密的电话里,我可以想像他们那一脸茫然的表情里,渴望从你那里得到一点点信息,或是表示惊讶,或是对自己即将要选择的路再给一次犹豫的机会来证明自己的慎重,再或是可以在家人同学朋友面前炫耀一下:"我对自己的未来是有长远考虑的".所以,写这篇文章的目的,我不是想讨论Android会不会真的死,你应不应该去学等这些问题,因为这就好像在讨论是先有鸡,还是先有蛋的问题,结果只是个人的片面理解而已,我只想给初入

【扣丁学堂】月薪1700元退伍兵哥蜕变为月薪万元IT男

IT教程视频:扣丁学堂 季晓健,2007年中专毕业后,谋求到一份还算稳定的工作,在某市药品仓库当管理员,月薪1700元.这份工作在父母.亲戚看来还算不错,但小季心里却并不这么认为.他从即将退休的50多岁的老员工身上看见了自己的未来 -- 在一成不变且没有前途的工作中虚度时光,如果不做出改变,未来的自己也将是这样熬到退休!小季想想都觉得可怕,改变现状成为他内心深处的渴望! 在深思熟虑之后,小季做出了人生的第一次改变 --入伍当兵.2008年,小季应征入伍,这是一条可以改变命运的选择 -- 中国很多

【扣丁学堂】10个理由让你继续干IT

每日一课:扣丁学堂 作为iOS与Android培训领头羊的扣丁学堂,对iOS与Android的研究都是走在互联网发展的潮流最前沿,把最新最好的技术教导给学生. 在课程体系外,还有很多有趣的IT资讯分享给大家: 我曾在"正规"IT这个行当中几进几出.已经从挫折这所学校里面了解到了许多坚守下来的理由.说实话,或多或少地,上述每一条我都有做不到的地方.当你真正了解了干IT的基本理由之后,你就会知道,是IT而不是别的职业能够满足技术头脑的更多需求. 1.钱,钱,钱 对,我们努力工作就是为了赚钱

【扣丁学堂】苹果的百年圆梦之路,你知道吗?

每日一课:扣丁学堂 近年来的苹果发布会,大有"过年"的趋势,最早的时候,全世界满怀期待,苹果也总能推出革命性产品,缔造了一个又一个经典瞬间,特别是 iPhone3Gs到iPhone4的设计升级,简直亮瞎了双眼,那种感觉就好像父亲在95年的时候,给家里买回来一台VCD机:随后,iPhone5s 的土豪金,iPhone6的大屏幕也都算是可圈可点的小革命. 那么苹果是如何发展成为世界一流互联网界的龙头坐拥霸主之位的呢? 扣丁学堂带你一起笑看市场,给iPhone找出一条平凡之路. 宏观看上去,

【扣丁学堂】全球IT员工收入,IT员工平均年薪27万

每日一课:扣丁学堂 中国IT员工工资排名多少你知道吗?专业的IT教育扣丁学堂带你一起了解:中国 IT 专业人员的平均年薪为 42689 美元 (约合人民币 272142 元) ,而印度为 41213 美元,美国为 132877 美元. MyHiringClub.com 对全球约 1 万家企业的薪水进行了调查,评出了各国处于职业生涯中期的 IT 专业人员的平均薪水.数据显示,中国 IT 专业人员的平均年薪为 42689 美元,排名第 13 位,同比增长 7%. 此外,印度 IT 专业人员的平均薪水

【扣丁学堂】程序员:细节决定成败

每日一课:扣丁学堂 你知道在线教育吗?你知道在哪可以学到更多更丰富的互联网专业知识吗? 没错,扣丁学堂可以带给你更快捷更方便的学习体验,让你快速跻身互联网专业领域,实现年薪十万的梦想. 下面,扣丁将会带你走进IT行业,浅谈成为优秀程序员应该养成的习惯. 首先,所有的程序都需要某种形式的日志记录建立在它们之上,以便我们可以观察到它正在做什么.这尤其在程序出错时就显得非常重要.一个优秀的程序员和一个糟糕的程序员之间的一个不同之处是一个优秀的程序员会增加日志或其他工具以便在程序失败时方便调试. 当程序

扣丁学堂邀你一起“移”生万物

全球移动互联网大会(Global Mobile Internet Conference 简称GMIC)每年都汇聚了来自全球移动互联网顶尖公司的创新领袖(点击阅读原文给你看).大会在北京国家会议中心隆重举行.据了解,本届在京举行的GMIC将以"Mobile Everything! 「移」生万物"为主题,旨在推动中国互联网事业发展,据悉本次的展览规模是上届的三倍.GMIC每年两次,分别在北京(5月)和硅谷(10月)各举办一次,是不是赶脚bigger and bigger. 其实GMIC之所

【扣丁学堂】霍金:黑洞或是通往平行宇宙的通道

本文出自:扣丁学堂 据国外媒体报道,史蒂芬-霍金在斯德哥尔摩举行的学术会议上提出一项理论称,被黑洞捕获的不幸太空旅行者将无法返回他们自己的宇宙,而是能够逃离到另外的时空.黑洞事实上并非是人们所想象的那样摧毁一切,它可能是前往一个平行宇宙的通道. 霍金提出的理论是为了解答困扰科学家们数十年的黑洞悖论 霍金在报告中称:"这是有可能的,只要黑洞非常巨大,而且如果它在旋转,那么它或许就是前往另一个宇宙的通道.但是你将无法返回到我们的宇宙中.因此尽管我热衷于太空飞行,但是我不会想要尝试通过黑洞."