0%

应广大用户要求,今天打算把壁纸程序改改,加上保存已下载壁纸的功能,但是有个问题,就是我自己的机器(MileStone)不读SD卡,提示SD卡为空白或者SD卡已损坏,导航一系列的功能不能用。貌似很多MS用户都有这样的问题,不知是不是MOTO哪里设计失误?所以为了不让程序异常,就得先检测一下SD卡是否可用,其实很简单:

        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {   
                setTitle("SD可用");
            }else {   
                setTitle("SD不可用");
            }

因为Android程序涉及到与服务器通讯,比较简单的一个方法就是直接访问Web服务器,与服务器端脚本(php,asp,jsp等)通讯,所以为了方便记忆,给博客新加了PHP开发这样一个分类。 今天学习PHP生成HTML。开发服务端程序的时候,为了方便,没有生成HTML,但这几天查看服务器日志发现,访问量没多少,CPU占用却比较高,所以今天找了些资料,准备生成静态HTML,每隔一段时间自动更新。 既然需要每隔一段时间自动更新,那肯定实现不了真正的完全静态了,因为要检测间隔时间嘛,这个功能不可能用HTML来实现。 但是即使这样,也节省了不少资源,因为至少在指定的时间内,不用重新读取数据库,只要读取已经生成的文件就可以了(相当于缓存)。 下面来实现: 第一步,伪静态(这一步非必要,仅仅是为了SEO,不需要可跳过) 这一步可以编辑根目录下的http.ini或.htaccess文件,如果没有可以新建,不支持该功能就找主机商吧。具体怎么写Google吧。编辑完http.ini或.htaccess文件还要修改相关文件的链接。 第二步,也是关键的一步,检测检测间隔时间,生成HTML 在文件开头加入以下代码:

ob_start();
$htmlfile='a.html';//这是生成的文件名,自己可以根据传入的ID什么的构造
if (file_exists($htmlfile))
{
 $filetime = filemtime($htmlfile);
 if (($filetime + 864000) > time())  //判断上次生成HTML文件是否超过240小时,若没有才直接输出文件内容
 {
  echo(file_get_contents($htmlfile));
  exit(0);
 }
}

注意第一名ob_start();,这个就是开始缓存,就是这句话以下的内容都会做为缓存,因为我们等下只会把缓存放入HTML文件,并不是整个完整的HTML文件,所以,如果要减小生成的文件体积,只要把这个放在动态内容之前就可以了,并不一定要放文件第一行。 下面是生成HTML的代码,放最低部。同样,为了减少文件体积,也可以放在动态内容结果以后。

<?
define("HTMLMETA","<!-- date("Y-m-d H:i:s")."-->");
$buffer = ob_get_flush();
$fp = fopen($htmlfile, "w");
if ($fp)
{
 fwrite($fp, $buffer.HTMLMETA);
 fclose($fp);
}else{
echo "打开失败";
}
?>

完了看效果,第一次访问,查看源文件,看最后一行,再刷新,再看最后一行,可以发现多出了一行注释,就是生成时间。当你再刷新时,生成时间并没有变,说明并没有重新生成。

这个注册监听自定义协议,就是指浏览器在打开指定协议的时候,会调用你的程序来处理,而不是使用浏览器处理。这样一来,在程序开发中,很多UI的东西都可以放在网页中,简单程序开发步骤,当需要Android处理时,写个自定义协议,调用相应的Activity。 下面来看例子: 在AndroidManifest.xml中,定义Activity的Intent-filter

            <intent-filter>
                <action android:name="android.intent.action.VIEW" />  
                <category android:name="android.intent.category.DEFAULT" />  
                <category android:name="android.intent.category.BROWSABLE" />  
                    <data android:scheme="sf" /> 
            </intent-filter>

VIEW,DEFAULT和BROWSABLE一个都不能少 最后的scheme是注册sf://这样的协议,当网页链接到这种协议的时候,就调用这个程序。 下面是程序中的接收代码:

        final Intent intent = getIntent();   
        final Uri uri = intent.getData(); 
        setTitle(String.valueOf(uri));

把URI写在标题上 至于测试,自己写个HTML测试一下吧。 源代码: [download id=”10”] 高清壁纸下一版本将会采用此方法实现。

tabhost有多个标签,如果各个标签下的内容都在OnCreate里载入的话,势必造成资源浪费,所以我们可以监听切换标签事件,在点击相应标签时载入相应内容。

tabHost.setOnTabChangedListener(changeLis);
OnTabChangeListener changeLis=new OnTabChangeListener(){
    @Override
    public void onTabChanged(String tabId) {
        // TODO Auto-generated method stub
        setTitle(tabId);
        
    }
    
};

这里把tabId显示标题上了,当然在实际应用中,可以写个判断,根据tabId做相应的处理。

最近遇到一件奇怪的事情,把APK文件传到虚拟主机上,用浏览器访问下载时,提示404,文件不存在,可是FTP里看到文件明明就存在。搜索了一下,得知在虚拟主机后台设置一下MIEI就可以解决,因为之前不知道APK的MIME该怎么填,APK又是压缩文件,结果就填了ZIP的application/x-compressed。还真的能下载了,但是下载下来默认会把扩展名改为ZIP,于是又搜了下APK的MIME类型,结果是 application/vnd.android.package-archive,现在问题解决。

下面的函数可以下载文件,并保存到指定目录。有点简单,只有一个URL的参数,可以自己加上保存目录,以及获取文件类型再生成相应的文件名,这样就完美了。

public void down_file(String url) throws IOException{
        //下载函数   	
        URL myURL = new URL(url);
        URLConnection conn = myURL.openConnection();
        conn.connect();
        InputStream is = conn.getInputStream();
        if (is == null) throw new RuntimeException("stream is null");
        //把文件存到path
        String path="/sdcard/temp.apk";
        OutputStream os = new FileOutputStream(path);    
        byte buf[] = new byte[1024];  
        do
          {
            int numread = is.read(buf);
            if (is.read(buf) == -1)
            {
              break;
            }
            os.write(buf, 0, numread);           
          } while (true);
       
            is.close();
            os.close();
               
    }

今天学习通知栏Notification使用自定义视图方法,这里以显示进度条ProgressBar为例,具体效果不上图了,请参考在Android Market下载软件时通知栏的效果。 布局XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<Button android:id="@+id/bt1"
    android:layout_height="wrap_content"
    android:layout_width="fill_parent"
    android:text="Notification测试"
/>
<Button android:id="@+id/bt2"
    android:layout_height="wrap_content"
    android:layout_width="fill_parent"
    android:text="清除Notification"
/>
</LinearLayout>

跟前面学习notification的例子一样,没改一个字。 既然要使用自定义的布局,当然要自己写xml文件:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:orientation="vertical"
  >
 <TextView android:id="@+id/down_tv" 
               android:layout_width="wrap_content"    
               android:layout_height="fill_parent" 
               android:textSize="20sp" 
               android:textColor="#000000"
               android:text="下载中"
               />   
<ProgressBar android:id="@+id/pb" 
             android:layout_width="260dip" 
             android:layout_height="wrap_content" 
             style="?android:attr/progressBarStyleHorizontal"
             android:layout_gravity="center_vertical"/>          
</LinearLayout>

一个TextView显示下载中,下面一根进度条显示当前进度 程序代码:

package com.pocketdigi.Notification;

import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.RemoteViews;

public class main extends Activity {
    /** Called when the activity is first created. */
    int notification_id=19172439;
    NotificationManager nm;
    Handler handler=new Handler();
    Notification notification;
    int count=0;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        Button bt1=(Button)findViewById(R.id.bt1);
        bt1.setOnClickListener(bt1lis);
        Button bt2=(Button)findViewById(R.id.bt2);
        bt2.setOnClickListener(bt2lis);
        //建立notification,前面有学习过,不解释了,不懂看搜索以前的文章
        nm=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);
        notification=new Notification(R.drawable.home,"图标边的文字",System.currentTimeMillis());
        notification.contentView = new RemoteViews(getPackageName(),R.layout.notification); 
        //使用notification.xml文件作VIEW
        notification.contentView.setProgressBar(R.id.pb, 100,0, false);
        //设置进度条,最大值 为100,当前值为0,最后一个参数为true时显示条纹
        //(就是在Android Market下载软件,点击下载但还没获取到目标大小时的状态)
        Intent notificationIntent = new Intent(this,main.class); 
        PendingIntent contentIntent = PendingIntent.getActivity(this,0,notificationIntent,0); 
        notification.contentIntent = contentIntent;        
    }
    OnClickListener bt1lis=new OnClickListener(){

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            showNotification();//显示notification
            handler.post(run);
        }
        
    };
    Runnable run=new Runnable(){

        @Override
        public void run() {
            // TODO Auto-generated method stub	
            count++;
            notification.contentView.setProgressBar(R.id.pb, 100,count, false);
            //设置当前值为count
            showNotification();//这里是更新notification,就是更新进度条
            if(count<100) handler.postDelayed(run, 200);
            //200毫秒count加1
        }
        
    };
    OnClickListener bt2lis=new OnClickListener(){

        @Override
        public void onClick(View v) {
            nm.cancel(notification_id);
            //清除notification
        }
        
    };
    public void showNotification(){
        nm.notify(notification_id, notification);   	
    }
}

就这样。源代码下载:[download id=”9”]

因为Android手机机型众多,屏幕分辨率有很多种,相对于IPHONE来说,在设计图标的时候就麻烦点,需要设计对应分辨率的图标,不然显示效果不好,以下是收集的用得最多的几种图标分辨率。hdpi对应800X480或854X480分辨率的手机,mdpi对应480X320分辨率的手机,ldpi对应320X240分辨率的手机。 类型 hdpi mdpi ldpi ICON 72*72 48*48 36*36 Notification图标 48*48 32*32 24*24 标签Tab图标 48*48 32*32 24*24

近几天因为在写高清壁纸的服务器端(基于PHP+MySql),所以好几天没更新博客了,顺便汇报一下高清壁纸的开发进度:服务器端已经改写,原来是一条数据一条数据加,现在是Flash批量上传图片,自动添加数据(这是后台,大家当然看不到啦)。另外,图片数据都放到自己的虚拟主机上了,所以大家可能觉得这几天下载图片特别慢。原来放POCO,速度比较快,但是毕竟是免费的,不放心,怕哪天被人发现了大流量下载,把我帐号图片删了,到时哭都来不及,而且那样也实现不了上传自动添加数据。新版客户端方面,目前多语言以及HVGA支持都已经完成,现在在做下载进度条(因为服务器稍慢,怕有些性子急的同学等不了)。汇报完毕,开始今天学习。今天的这段代码是网上找的,自己做了些小改,通过模拟器测试。文件下载进度条控制(就是为了高清壁纸加个进度条),自己研究了好久,但是进度条只能显示缓存写入文件的进度,不能显示下载进度。找了好久,终于找到一段用的代码,所以记录下来,大家分享。 布局XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView  android:id="@+id/tv"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text=""
    />
<ProgressBar android:id="@+id/down_pb"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content"
    android:max="100"
    style="?android:attr/progressBarStyleHorizontal"
/>
</LinearLayout>

这个就不用解释了吧,两个控件,一个是TextView,一个是横向条状进度条 程序main.java:

package com.pocketdigi.download;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

import org.apache.http.client.ClientProtocolException;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

public class main extends Activity {
    /** Called when the activity is first created. */
    ProgressBar pb;
    TextView tv;
    int   fileSize;
    int   downLoadFileSize;
    String fileEx,fileNa,filename;
    private Handler handler = new Handler()
      {
        @Override
        public void handleMessage(Message msg)
        {//定义一个Handler,用于处理下载线程与UI间通讯
          if (!Thread.currentThread().isInterrupted())
          {
            switch (msg.what)
            {
              case 0:
                pb.setMax(fileSize);
              case 1:
                pb.setProgress(downLoadFileSize);
                int result = downLoadFileSize * 100 / fileSize;
                tv.setText(result + "%");
                break;
              case 2:
                Toast.makeText(main.this, "文件下载完成", 1).show();
                break;

              case -1:
                String error = msg.getData().getString("error");
                Toast.makeText(main.this, error, 1).show();
                break;
            }
          }
          super.handleMessage(msg);
        }
      };
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        pb=(ProgressBar)findViewById(R.id.down_pb);
        tv=(TextView)findViewById(R.id.tv);
        new Thread(){
            public void run(){
                try {
                    down_file("http://wallpaper.pocketdigi.com/upload/1/bigImage/1284565196.jpg","/sdcard/");
                    //下载文件,参数:第一个URL,第二个存放路径
                } catch (ClientProtocolException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }.start();
        

    }
    public void down_file(String url,String path) throws IOException{
        //下载函数   	
        filename=url.substring(url.lastIndexOf("/") + 1);
        //获取文件名
        URL myURL = new URL(url);
        URLConnection conn = myURL.openConnection();
        conn.connect();
        InputStream is = conn.getInputStream();
        this.fileSize = conn.getContentLength();//根据响应获取文件大小
        if (this.fileSize <= 0) throw new RuntimeException("无法获知文件大小 ");
        if (is == null) throw new RuntimeException("stream is null");
        FileOutputStream fos = new FileOutputStream(path+filename);
        //把数据存入路径+文件名
        byte buf[] = new byte[1024];
        downLoadFileSize = 0;
        sendMsg(0);
        do
          {
        	//循环读取
            int numread = is.read(buf);
            if (numread == -1)
            {
              break;
            }
            fos.write(buf, 0, numread);
            downLoadFileSize += numread;
            
            sendMsg(1);//更新进度条
          } while (true);
        sendMsg(2);//通知下载完成
        try
          {
            is.close();
          } catch (Exception ex)
          {
            Log.e("tag", "error: " + ex.getMessage(), ex);
          }
        
    }
    private void sendMsg(int flag)
    {
        Message msg = new Message();
        msg.what = flag;
        handler.sendMessage(msg);
    }	 

    
}

源代码: [download id=”8”]

IMEI是国际移动设备身份码的缩写,每台手机都有一个唯一的IMEI号码(貌似有国产山寨机用同一个IMEI)。IMSI是国际移动用户识别码缩写,每张SIM卡都有唯一的一个IMSI号码。因为他们都是唯一的,有些时候我们可以用他们来识别用户身份,不用再输帐号登录(这样一来,没有IMEI和IMSI的android MP4,平板电脑就用不了了),以下是读取方法:

       TelephonyManager tm = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
        String imei = tm.getDeviceId();  
        String imsi =tm.getSubscriberId();