diff --git a/soft1614080902427/Big Big World.mp3 b/soft1614080902427/Big Big World.mp3 new file mode 100644 index 000000000..65345ce20 Binary files /dev/null and b/soft1614080902427/Big Big World.mp3 differ diff --git a/soft1614080902427/I23KW.png b/soft1614080902427/I23KW.png new file mode 100644 index 000000000..50b078000 Binary files /dev/null and b/soft1614080902427/I23KW.png differ diff --git a/soft1614080902427/Soft1614080902427Activity.java b/soft1614080902427/Soft1614080902427Activity.java index cbb41d04e..9f3532a50 100644 --- a/soft1614080902427/Soft1614080902427Activity.java +++ b/soft1614080902427/Soft1614080902427Activity.java @@ -2,6 +2,6 @@ public class Soft1614080902427Activity{ public static void main(String[] args){ - System.out.println("Hello World!"); + System.out.println("Hello World!123"); } } diff --git a/soft1614080902427/java/edu/hzuapps/androidlabs/soft1614080902427/Downloader.java b/soft1614080902427/java/edu/hzuapps/androidlabs/soft1614080902427/Downloader.java new file mode 100644 index 000000000..e880e907a --- /dev/null +++ b/soft1614080902427/java/edu/hzuapps/androidlabs/soft1614080902427/Downloader.java @@ -0,0 +1,79 @@ +package edu.hzuapps.androidlabs.soft1614080902427; + +import android.os.AsyncTask; +import android.util.Log; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.Reader; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.charset.StandardCharsets; + + +public class Downloader { + private final static String TAG = Downloader.class.getSimpleName(); + + private final DownloaderListener listener; + + public Downloader(DownloaderListener listener) { + this.listener = listener; + } + + public void createTask(String url) { + + new AsyncTask() { + public String url; + + @Override + protected ByteArrayOutputStream doInBackground(String[] params) { + this.url = params[0]; + + HttpURLConnection connection = null; + InputStream is = null; + ByteArrayOutputStream out = null; + try { + connection = (HttpURLConnection) new URL(this.url).openConnection(); + is = connection.getInputStream(); + out = new ByteArrayOutputStream(); + byte[] buffer = new byte[256]; + int bytesRead; + while((bytesRead = is.read(buffer))!=-1){ + out.write(buffer,0,bytesRead); + } + } catch (Exception e) { + Log.e(TAG,"下载 " +url + "出现错误: "+e.toString()); + } + return out; + } + + @Override + protected void onPreExecute() { + super.onPreExecute(); + } + + @Override + protected void onPostExecute(ByteArrayOutputStream stream) { + super.onPostExecute(stream); + Downloader.this.listener.onDone(this.url, stream); + } + + @Override + protected void onProgressUpdate(Integer... values) { + super.onProgressUpdate(values); + } + + @Override + protected void onCancelled(ByteArrayOutputStream stream) { + super.onCancelled(stream); + listener.onError(this.url); + } + + }.execute(url); + } +} \ No newline at end of file diff --git a/soft1614080902427/java/edu/hzuapps/androidlabs/soft1614080902427/DownloaderListener.java b/soft1614080902427/java/edu/hzuapps/androidlabs/soft1614080902427/DownloaderListener.java new file mode 100644 index 000000000..632685c81 --- /dev/null +++ b/soft1614080902427/java/edu/hzuapps/androidlabs/soft1614080902427/DownloaderListener.java @@ -0,0 +1,17 @@ +package edu.hzuapps.androidlabs.soft1614080902427; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; + +public abstract class DownloaderListener { + public DownloaderListener() { + } + + public void onError(String url) { + + } + + public void onDone(String url, ByteArrayOutputStream stream) { + + } +} diff --git a/soft1614080902427/java/edu/hzuapps/androidlabs/soft1614080902427/Player.java b/soft1614080902427/java/edu/hzuapps/androidlabs/soft1614080902427/Player.java index 7fe347cab..ef33cd2a0 100644 --- a/soft1614080902427/java/edu/hzuapps/androidlabs/soft1614080902427/Player.java +++ b/soft1614080902427/java/edu/hzuapps/androidlabs/soft1614080902427/Player.java @@ -2,6 +2,9 @@ import android.content.Context; import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.Uri; import android.os.Bundle; import android.app.Activity; import android.os.Environment; @@ -21,10 +24,14 @@ import com.google.gson.Gson; import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; import java.util.Random; @@ -32,12 +39,16 @@ public class Player extends Activity implements View.OnClickListener { private final String TAG = this.getClass().getSimpleName(); + private final static String Host = "https://raw.githubusercontent.com/harytfw/android-labs-2018/master/soft1614080902427"; + private final static String songListURL = Host+"/song.json"; + private ListView listView = null; - protected LocalStorage localStorage; + private LocalStorage localStorage; private SettingHolder mySetting; private FileScanner scanner = new FileScanner(); - + private Gson gson = new Gson(); + private int downloadCount = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -56,10 +67,10 @@ public void onClick(View v) { } //读取设置 - public void readSetting(){ + public void readSetting() { - mySetting = (SettingHolder)localStorage.readFromJsonFile("data.json",SettingHolder.class); - if(mySetting==null) { + mySetting = (SettingHolder) localStorage.readFromJsonFile("data.json", SettingHolder.class); + if (mySetting == null) { mySetting = new SettingHolder();//读取默认设置 } @@ -77,27 +88,26 @@ public void onItemClick(AdapterView parent, View view, int position, long id) } //保存设置到 data.json - public void saveSetting(){ - Log.i(TAG,"保存设置到data.json"); - localStorage.writeToJsonFile("data.json",mySetting); - Toast.makeText(this,"设置已保存", Toast.LENGTH_SHORT).show(); + public void saveSetting() { + Log.i(TAG, "保存设置到data.json"); + localStorage.writeToJsonFile("data.json", mySetting); + Toast.makeText(this, "设置已保存", Toast.LENGTH_SHORT).show(); } - //创建选项菜单 @Override - public boolean onCreateOptionsMenu(Menu menu){ - getMenuInflater().inflate(R.menu.simple_menu,menu); + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.simple_menu, menu); return true; } //选项菜单点击事件 @Override - public boolean onOptionsItemSelected(MenuItem item){ - switch(item.getItemId()){ + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { case R.id.menu_item_scan: - mySetting.items=scanner.scan(); - Toast.makeText(this,"扫描完成!",Toast.LENGTH_SHORT).show(); + mySetting.items = scanner.scan(); + Toast.makeText(this, "扫描完成!", Toast.LENGTH_SHORT).show(); SongAdapter adapter = (SongAdapter) listView.getAdapter(); //刷新原有的数据 adapter.items.clear(); @@ -106,16 +116,107 @@ public boolean onOptionsItemSelected(MenuItem item){ saveSetting(); break; case R.id.menu_item_setting: - Toast.makeText(this,item.getTitle(),Toast.LENGTH_SHORT).show(); + Toast.makeText(this, item.getTitle(), Toast.LENGTH_SHORT).show(); break; case R.id.menu_item_back: Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_HOME); startActivity(intent); + break; + case R.id.menu_item_syncSong: + this.syncSongList(); + break; } return true; } + protected void syncSongList() { + if(!checkNetwork()){ + return; + } + makeToast("开始同步歌单"); + Downloader dl =new Downloader(new DownloaderListener() { + @Override + public void onError(String url) { + super.onError(url); + Log.i(TAG,url+ " 下载失败失败"); + makeToast("url 下载失败失败"); + } + + @Override + public void onDone(String url, ByteArrayOutputStream out) { + String json = null; + try { + json = out.toString("utf-8"); + } catch (UnsupportedEncodingException e) { + Log.e(TAG,e.toString()); + json = null; + } + + if(json==null){ + makeToast("同步失败"); + return; + } + + Log.i(TAG,"歌单JSON:"+json); + makeToast("同步完成,开始解析并下载歌曲文件"); + + if(mySetting==null){ + makeToast("解析歌单信息失败"); + return; + } + + mySetting = gson.fromJson(json, SettingHolder.class); + SongAdapter adapter = (SongAdapter) listView.getAdapter(); + adapter.items.clear(); + adapter.items.addAll(mySetting.items); + adapter.notifyDataSetChanged(); + saveSetting(); + + syncSongFile(); + } + }); + dl.createTask(this.songListURL); + } + + protected void syncSongFile(){ + this.downloadCount = mySetting.items.size(); + if(this.downloadCount != 0){ + this.setTitle("文件还在下载..."); + } + for (SongItem item : mySetting.items) { + Downloader dl = new Downloader(new DownloaderListener() { + @Override + public void onError(String url) { + downloadCount--; + if(downloadCount==0){ + setTitle("文件下载完成"); + } + makeToast(url + " 下载出现错误!"); + } + @Override + public void onDone(String url, ByteArrayOutputStream baos) { + String fileName = url.substring( url.lastIndexOf('/')+1, url.length() ); + fileName = Uri.decode(fileName); + if(baos==null){ + makeToast(fileName + "下载失败!"); + } + else if(localStorage.writeFile(fileName,baos)) { + makeToast(fileName + "下载完成!"); + } + downloadCount--; + if(downloadCount==0){ + setTitle("文件下载完成"); + } + } + }); + + String url = Uri.encode(item.getMp3()); + url = this.Host +"/"+ url; + Log.i(TAG,"开始下载: "+url); + dl.createTask(url); + } + } //设置透明状态栏(沉浸式状态栏) protected void setStatusBarTranslucent(boolean makeTranslucent) { if (makeTranslucent) { @@ -125,6 +226,27 @@ protected void setStatusBarTranslucent(boolean makeTranslucent) { } } + protected boolean checkNetwork(){ + ConnectivityManager connMgr = (ConnectivityManager) + getSystemService(Context.CONNECTIVITY_SERVICE); + // 检查当前激的网络 + NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); + boolean mConnected; + if (networkInfo != null && networkInfo.isConnected()) { + mConnected = true; + } else { + mConnected = false; + } + + if(!mConnected){ + makeToast("网络未连接"); + return false; + } + else{ + return true; + } + } + class SongAdapter extends ArrayAdapter {//SongItem 与 ListView 的适配器 private List items; //保存整个列表 private SongViewHolder songItemHolder; //临时的holder @@ -172,6 +294,13 @@ public View getView(int pos, View convertView, ViewGroup parent) {//? return v; } } + + + + + private void makeToast(String str) { + Toast.makeText(this, str, Toast.LENGTH_SHORT).show(); + } } @@ -197,24 +326,41 @@ public void setSingerName(String singerName) { private String singerName; + public SongItem(String songName, String singerName) { + this(songName, singerName, ""); + } + + private String mp3; + + public String getMp3() { + return mp3; + } + + public void setMp3(String mp3) { + this.mp3 = mp3; + } + + public SongItem(String songName, String singerName, String mp3) { this.songName = songName; this.singerName = singerName; + this.mp3 = mp3; } - } -class SettingHolder{ +class SettingHolder { public List items = null; - public SettingHolder(){ + + public SettingHolder() { items = new ArrayList<>(); } } //模拟的文件扫描类 -class FileScanner{ +class FileScanner { private List items; - public FileScanner(){ + + public FileScanner() { items = new ArrayList(); items.add(new SongItem("后来", "刘若英")); items.add(new SongItem("无情的雨无情..", "齐秦")); @@ -228,11 +374,12 @@ public FileScanner(){ items.add(new SongItem("风雨无阻", "周华健")); } - public List scan(){ + + public List scan() { List temp = new ArrayList<>(); temp.addAll(items); Random random = new Random(); - for(int i=0;i<5;i++){//随机删除5首歌 + for (int i = 0; i < 5; i++) {//随机删除5首歌 temp.remove(random.nextInt(temp.size())); } return temp; @@ -252,17 +399,13 @@ public LocalStorage(Context mContext) { } public boolean writeToJsonFile(String filename, Object obj) { - if (!isExternalStorageWritable()) { - Log.e(TAG, "外部存储不可写!"); - return false; - } File dir = getPrivateExtStorageDir(""); File file = new File(dir, filename); String json = gson.toJson(obj); try { FileWriter writer = new FileWriter(file); - Log.i(TAG,"写入数据: "+file.getAbsolutePath()); + Log.i(TAG, "写入数据: " + file.getAbsolutePath()); writer.write(json); writer.flush(); writer.close(); @@ -302,6 +445,45 @@ public Object readFromJsonFile(String filename, Class classType) { } + public boolean writeFile(String filename,ByteArrayOutputStream baos) { + return this.writeFile(filename,baos.toByteArray()); + } + + public boolean writeFile(String filename,byte[] data){ + return this.writeFile(filename,data,false); + } + + public boolean writeFile(String filename,byte[] data,boolean overwrite){ + if (!isExternalStorageWritable()) { + Log.e(TAG, "外部存储不可写!"); + return false; + } + + File dir = getPrivateExtStorageDir(""); + File file = new File(dir, filename); + if(!file.exists()){ + try { + file.createNewFile(); + } catch (IOException e) { + Log.e( TAG,filename + "创建失败"); + } + } + else if(!overwrite){ + return true; + } + + try { + FileOutputStream fos = new FileOutputStream(file); + fos.write(data); + return true; + } catch (FileNotFoundException e) { + Log.e( TAG,filename + "文件不存在"); + return false; + }catch (IOException e ){ + Log.e(TAG,filename + "写入失败"); + return false; + } + } /* Checks if external storage is available for read and write */ private boolean isExternalStorageWritable() { @@ -324,7 +506,7 @@ private boolean isExternalStorageReadable() { private File getPrivateExtStorageDir(String dirName) { File file = new File(mContext.getExternalFilesDir(null), dirName); - if (!file.mkdirs()) { + if (!file.exists() && !file.mkdirs()) { Log.e(TAG, "目录无法创建!"); } return file; diff --git a/soft1614080902427/java/edu/hzuapps/androidlabs/soft1614080902427/Soft1614080902427Activity.java b/soft1614080902427/java/edu/hzuapps/androidlabs/soft1614080902427/Soft1614080902427Activity.java index dabb1cb9f..e40eb9593 100644 --- a/soft1614080902427/java/edu/hzuapps/androidlabs/soft1614080902427/Soft1614080902427Activity.java +++ b/soft1614080902427/java/edu/hzuapps/androidlabs/soft1614080902427/Soft1614080902427Activity.java @@ -16,8 +16,8 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_soft1614080902427); - logoBtn = (TextView)findViewById(R.id.textview); + } @Override diff --git a/soft1614080902427/manifests/AndroidManifest.xml b/soft1614080902427/manifests/AndroidManifest.xml index 59a646c62..061a59894 100644 --- a/soft1614080902427/manifests/AndroidManifest.xml +++ b/soft1614080902427/manifests/AndroidManifest.xml @@ -19,6 +19,13 @@ + - \ No newline at end of file + + + + + + + diff --git a/soft1614080902427/report6.md b/soft1614080902427/report6.md new file mode 100644 index 000000000..9498cb4fb --- /dev/null +++ b/soft1614080902427/report6.md @@ -0,0 +1,48 @@ +## 实验目标 + +1. 掌握Android网络访问方法; +2. 理解XML和JSON表示数据的方法。 + +## 实验内容(选做一) + +1. 在个人目录中创建一个表示数据的XML或JSON文件; +2. 数据文件代码提交之后从GitHub获取文件URL; +3. 在应用中通过网络编程访问GitHub的数据文件; +4. 在应用中解析并显示文件所包含的数据; +5. 将应用运行结果截图。 + +## 实验内容(选做一) + +1. 从网络下载一个文件(图片、MP3、MP4); +2. 保存到手机,在应用中使用文件; +3. 将应用运行结果截图。 + + +## 实验步骤 + +1. 分析:歌单文件用JSON方式存放在github上(https://raw.githubusercontent.com/harytfw/android-labs-2018/master/soft1614080902427/song.json) + 在APP中用GSON库解析JSON,获得歌曲的mp3文件名,然后与网站域名拼接,得到歌曲的下载链接:https://raw.githubusercontent.com/harytfw/android-labs-2018/master/soft1614080902427/%E4%B9%9D%E9%BE%99%E8%B5%9E.mp3 + +2. 因为与下载文件有关的网络操作不能放在APP的主线程中,所以新建一个 [Downloader](https://github.com/harytfw/android-labs-2018/blob/master/soft1614080902427/java/edu/hzuapps/androidlabs/soft1614080902427/Downloader.java)类 + +用来实例化AsyncTask,进行后台的网络操作。创建一个 DownloaderListener 类实现简单的监听器功能,监听下载完成和下载错误的后续操作 + +3. 根据实际需求,给 SongItem 添加一个类型是String mp3 的属性. + +4. 下载的mp3文件可以先保存到内存中, 也就是写入到 ByteArrayOutputStream 中,等下载完整个mp3文件后,在写入手机存储中。减少对手机性能的影响 + +5. URL链接中不能直接存放中文字符和某些特定字符(空格),所以需要进行URL编码,不然直接出错。我们可以利用Android自带的Uri库对url编码 + +## 实验结果 + +![](https://github.com/harytfw/android-labs-2018/blob/master/soft1614080902427/screenshot1.png) +![](https://github.com/harytfw/android-labs-2018/blob/master/soft1614080902427/screenshot2.png) +![](https://github.com/harytfw/android-labs-2018/blob/master/soft1614080902427/screenshot3.png) + +## 实验心得 + +AsyncTask类的泛型类型对应着 doInBackground 参数的类型,onProgressUpdate 参数的类型,doInBackground 返回的参数类型 +这是从StackOverflow:https://stackoverflow.com/questions/9671546/asynctask-android-example 复制下来的图片 +![](https://github.com/harytfw/android-labs-2018/blob/master/soft1614080902427/I23KW.png) + +因为使用到了网络权限,那么一定要在 AndroidManifest.xml 里声明对应的网络权限,否则无法访问网络 diff --git a/soft1614080902427/screenshot1.png b/soft1614080902427/screenshot1.png new file mode 100644 index 000000000..4cb3ae59f Binary files /dev/null and b/soft1614080902427/screenshot1.png differ diff --git a/soft1614080902427/screenshot2.png b/soft1614080902427/screenshot2.png new file mode 100644 index 000000000..ce9f89c05 Binary files /dev/null and b/soft1614080902427/screenshot2.png differ diff --git a/soft1614080902427/screenshot3.png b/soft1614080902427/screenshot3.png new file mode 100644 index 000000000..9e24bb9d7 Binary files /dev/null and b/soft1614080902427/screenshot3.png differ diff --git a/soft1614080902427/song.json b/soft1614080902427/song.json new file mode 100644 index 000000000..2f0dc0edb --- /dev/null +++ b/soft1614080902427/song.json @@ -0,0 +1,24 @@ +{ + "items": [ + { + "songName": "Big Big World", + "singerName": "Emilia", + "mp3": "Big Big World.mp3" + }, + { + "songName": "我欲成仙", + "singerName": "刘欢", + "mp3": "我欲成仙.mp3" + }, + { + "songName": "勇气", + "singerName": "梁静茹", + "mp3": "勇气.mp3" + }, + { + "songName": "九龙赞", + "singerName": "群星", + "mp3": "九龙赞.mp3" + } + ] +} \ No newline at end of file diff --git "a/soft1614080902427/\344\271\235\351\276\231\350\265\236.mp3" "b/soft1614080902427/\344\271\235\351\276\231\350\265\236.mp3" new file mode 100644 index 000000000..da8984b5f Binary files /dev/null and "b/soft1614080902427/\344\271\235\351\276\231\350\265\236.mp3" differ diff --git "a/soft1614080902427/\345\213\207\346\260\224.mp3" "b/soft1614080902427/\345\213\207\346\260\224.mp3" new file mode 100644 index 000000000..b8daac34a Binary files /dev/null and "b/soft1614080902427/\345\213\207\346\260\224.mp3" differ diff --git "a/soft1614080902427/\346\210\221\346\254\262\346\210\220\344\273\231.mp3" "b/soft1614080902427/\346\210\221\346\254\262\346\210\220\344\273\231.mp3" new file mode 100644 index 000000000..3ec92467b Binary files /dev/null and "b/soft1614080902427/\346\210\221\346\254\262\346\210\220\344\273\231.mp3" differ